Factory pattern usually creates a base class for the concrete classes and the concrete classes then inherit from that base class. For a lot of applications, we need to know the number of the concrete classes this factory can create. For instance, a factory that creates the typical Shape objects (circle, rectangular, etc.) C# code example below:
public class ShapeFactory
{
public IShape GetShape(int shapeIndex)
{
IShape s = null;
const int color = 1;
const int thickness = 5;
switch (shapeIndex)
{
case 1: s = new Square(color, thickness);
break;
case 2: s = new Triangle(thickness);
break;
case 3: s = new Circle(color);
break;
}
return s;
}
}
The user may want to know how many kinds of shapes are supported by the program. I know 2 ways to do this:
Set the number as a constant in the factory class and make it
visible to public. The drawback is that every time you add a new
Shape, you have to manually increase the number of shapes.
Create a dynamic container (List in C#) that contains all instances
of the concrete objects the factory can create. The advantage is
that it can automatically figure out the number of Shapes it can
create, even if new Shape classes are added. The drawback is
obvious, every kind of Shapes have to be created together with the
Shape requested!
What is the best way to do this? Any best practice on this specific topic?
You could create an Enum that has the constants stored for you.
This also helps helps users by knowing the 'possibilities' by the IDE's auto complete features, plus it prevents the user from entering a number 'out of bounds' such as entering '4' in your example. (Mind you I generally write java... so C# isn't my forte, but you can do 'something' similar to this)
public class ShapeFactory
{
enum PossibleShapes {CIRCLE,
SQUARE,
TRIANGLE, // c# allows you to do this (extra comma) on constructors, not sure about Enums, and helps with reducing 'bad' line changes in git/etc.
};
public IShape GetShape(PossibleShapes whichShape)
{
IShape s = null;
switch (shapeCode)
{
case PossibleShapes.SQUARE : s = new Square(color, thickness);
break;
case PossibleShapes.TRIANGLE: s = new Triangle(thickness);
break;
case PossibleShapes.CIRCLE: s = new Circle(color);
break;
}
return s;
}
}
The "issue" of having to edit the class each time you add a new possibility is moot, because you WILL have to edit this class each time you do that, now you just have to edit the 'PossibleShapes' class too.
(Mind you, I still don't think this is proper usage of the Factory Pattern, because I have no clue where the 'color' and 'thickness' values are coming from, but at least this is better than using reflection)
Here is a Builder Pattern Example that I think does a better example encapsulating your object creation for you. (You could use the Factory Method pattern instead of having different named Methods for each Shape you want to 'get' within the builder)
Plus this allows the user to set the color/thickness themselves easily (can still have defaults, but I didn't put that into this code example)
Represents a product created by the builder
public class Shape
{
public Shape()
{
}
public int Color { get; set; }
public int Thickness { get; set; }
}
The builder abstraction
public interface IShapeBuilder
{
// Adding NotNull attribute to prevent null input argument
void SetColor([NotNull]string colour);
// Adding NotNull attribute to prevent null input argument
void SetThickness([NotNull]int count);
Shape GetShape();
}
Concrete builder implementation
public class ShapeBuilder : IShapeBuilder
{
private Shape _shape;
public ShapeBuilder()
{
}
public int GetNumberShapesPossible()
{
//return some # here
}
public void GetSquare(){
this._shape = new Square();
}
public void GetCircle(){
this._shape = new Circle();
}
public void SetColor(string color)
{
this._shape.Color = color;
}
public void SetThickness(int thickness)
{
this._shape.Thickness = thickness;
}
public Shape Build()
{
return this._shape;
}
}
The director
public class ShapeBuildDirector
{
public Shape Construct()
{
ShapeBuilder builder = new ShapeBuilder();
builder.GetCircle();
builder.SetColour(2);
builder.SetThickness(4);
return builder.GetResult();
}
}
You are going to have to change some code somewhere when you want to add new concrete classes to your library. Unless you plan on bundling the concrete classes as some kind of .dll There is just no way around that. There will have to be some edit to a builder/factory/etc somewhere.
You can store the types of shapes in an array then use Activator to create the instance. This takes care of indexing, count, and simplifies your creation function.
static class ShapeFactory
{
private static readonly Type[] _shapes = new Type[] { typeof(Square), typeof(Triangle), typeof(Circle) };
public static int FactorySize
{
get
{
return _shapes.Length;
}
}
public static IShape GetShape(int shapeIndex, params object[] ctorParams)
{
return (IShape)Activator.CreateInstance(_shapes[shapeIndex], ctorParams);
}
}
Related
For my project purpose I need to send metrics to AWS.
I have main class called SendingMetrics.
private CPUMetric _cpuMetric;
private RAMMetric _ramMetric;
private HDDMetric _hddMetric;
private CloudWatchClient _cloudWatchClient(); //AWS Client which contains method Send() that sends metrics to AWS
public SendingMetrics()
{
_cpuMetric = new CPUMetric();
_ramMetric = new RAMMetric();
_hddMetric = new HDDMetric();
_cloudwatchClient = new CloudwatchClient();
InitializeTimer();
}
private void InitializeTimer()
{
//here I initialize Timer object which will call method SendMetrics() each 60 seconds.
}
private void SendMetrics()
{
SendCPUMetric();
SendRAMMetric();
SendHDDMetric();
}
private void SendCPUMetric()
{
_cloudwatchClient.Send("CPU_Metric", _cpuMetric.GetValue());
}
private void SendRAMMetric()
{
_cloudwatchClient.Send("RAM_Metric", _ramMetric.GetValue());
}
private void SendHDDMetric()
{
_cloudwatchClient.Send("HDD_Metric", _hddMetric.GetValue());
}
Also I have CPUMetric, RAMMetric and HDDMetric classes that looks pretty much similar so I will just show code of one class.
internal sealed class CPUMetric
{
private int _cpuThreshold;
public CPUMetric()
{
_cpuThreshold = 95;
}
public int GetValue()
{
var currentCpuLoad = ... //logic for getting machine CPU load
if(currentCpuLoad > _cpuThreshold)
{
return 1;
}
else
{
return 0;
}
}
}
So the problem I have is that clean coding is not satisfied in my example. I have 3 metrics to send and if I need to introduce new metric I will need to create new class, initialize it in SendingMetrics class and modify that class and that is not what I want. I want to satisfy Open Closed principle, so it is open for extensions but closed for modifications.
What is the right way to do it? I would move those send methods (SendCPUMetric, SendRAMMetric, SendHDDMetric) to corresponding classes (SendCPUMetric method to CPUMetric class, SendRAMMEtric to RAMMetric, etc) but how to modfy SendingMetrics class so it is closed for modifications and if I need to add new metric to not change that class.
In object oriented languages like C# the Open Closed Principle (OCP) is usually achieved by using the concept of polymorphism. That is that objects of the same kind react different to one and the same message. Looking at your class "SendingMetrics" it's obvious that the class works with different types of "Metrics". The good thing is that your class "SendingMetrics" talks to a all types of metrics in the same way by sending the message "getData". Hence you can introduce a new abstraction by creating an Interface "IMetric" that is implemented by the concrete types of metrics. That way you decouple your "SendingMetrics" class from the concrete metric types wich means the class does not know about the specific metric types. It only knows IMetric and treats them all in the same way wich makes it possible to add any new collaborator (type of metric) that implements the IMetric interface (open for extension) without the need to change the "SendingMetrics" class (closed for modification). This also requires that the objects of the different types of metrics are not created within the "SendingMetrics" class but e.g. by a factory or outside of the class and being injected as IMetrics.
In addition to using inheritance to enable polymorphism and achiving OCP by introducing the interface IMetric you can also use inheritance to remove redundancy. Which means you can introduce an abstract base class for all metric types that implements common behaviour that is used by all types of metrics.
Your design is almost correct. You got 3 data retriever and 1 data sender. So it's easy to add more metric (more retriever) (open for extensions) without affecting current metrics (closed for modifications), you just need a bit more refactor to reduce duplicated code.
Instead of have 3 metrics classes look very similar. Only below line is different
var currentCpuLoad = ... //logic for getting machine CPU load
You can create a generic metric like this
internal interface IGetMetric
{
int GetData();
}
internal sealed class Metric
{
private int _threshold;
private IGetMetric _getDataService;
public Metric(IGetMetric getDataService)
{
_cpuThreshold = 95;
_getDataService = getDataService;
}
public int GetValue()
{
var currentCpuLoad = _getDataService.GetData();
if(currentCpuLoad > _cpuThreshold)
{
return 1;
}
else
{
return 0;
}
}
}
Then just create 3 GetMetric classes to implement that interface. This is just 1 way to reduce the code duplication. You can also use inheritance (but I don't like inheritance). Or you can use a Func param.
UPDATED: added class to get CPU metric
internal class CPUMetricService : IGetMetric
{
public int GetData() { return ....; }
}
internal class RAMMetricService : IGetMetric
{
public int GetData() { return ....; }
}
public class AllMetrics
{
private List<Metric> _metrics = new List<Metric>()
{
new Metric(new CPUMetricService());
new Metric(new RAMMetricService());
}
public void SendMetrics()
{
_metrics.ForEach(m => ....);
}
}
I don't really know how to formulate my issue it's a bit complicated for me, i'll try my best to explain.
I'm making a space game, i have a base class which represent places, and i want to have different type of places like planets, space stations, asteroïds, trading ships etc. The player can click on those objects and get informations.
So my classes looks like something like this:
public class Place {
public int placeId;
public string placeName;
public string placeDescription;
/* Place constructor */
}
public class Planet : Place {
/* Specific proprieties of planet */
public PlanetType planetType;
public int planetSize;
...
// Planet constructor
public Planet(int placeId, string placeName, string placeDescription, PlanetType planetType, int planetSize) : base(placeId, placeName, placeDescription) {
this.planetType = planetType;
this.planetSize = planetSize;
...
}
}
And i have a delegate which accept a function like selectPlace with Place in parameters because i don't want to make a delegate for each type of Place i have.
In another script which is supposed to show the information of any kind of Place, i recieves the Place object that the player clicked on. I think i found a solution, however is this correct to do something like this ?
private void updateSelectedPlaceUI(object sender, EventsController.PlaceEventArgs placeArgs){
// This is just a test, i should check which type of subclass it is before
Planet planetTest = placeArgs.Place as Planet; // So now i can use planetTest.planetType
}
And placing this in a switch case so i can handle any type. I just want to be able to get the proprieties from any derived class of Place in order to display them in UI. I would like to know a better way to achieve this.
But i'm wondering if my design is ok and necessary, it has been a while since i haven't used inheritance / polymorphism, and i feel like i'm doing it the wrong way.
I would propably make the UI part of showing the properties a specific place generic to accept something like a PropertyItem, you can decide the properties yourself.
public class PropertyItem
{
public string Text { get; set; }
public object Value { get; set; }
}
And then in your select method you would just call the abstract method of your base class (make your base class abstract as well)
public abstract class Place
{
...
public abstract IEnumerable<PropertyItem> GetProperties();
}
And now you can override this in your Planet
public class Planet : Place
{
...
public override IEnumerable<PropertyItem> GetProperties()
{
yield return new PropertyItem { Text = "Size", Value = this.planetSize };
}
}
And eventually you would use the GetProperties() method to get the properties of your place and show them in a tabular or what ever format your UI knows how to handle the PropertyItem type.
private void updateSelectedPlaceUI(object sender, EventsController.PlaceEventArgs placeArgs)
{
MyUserInterfaceWidget.DisplayProperties(placeArgs.Place.GetProperties());
}
I'm looking for a way to implement a double dispatch that can be extended for both methods and classes.
Until now I used basically three approaches:
the traditional procedural approach with a great switch (easy to add new functions, hard to add new classes)
the visitor pattern (quite similar: easy to add new visitors, hard to add new classes)
a simple interface approach (easy to add new classes, hard to add new functions)
I'm looking for a way to be able to add both new functions and new classes without having to modify the functions or existing classes.
This should not fail upon requesting a certain combination of object / function, at least not after a check I could do once after program startup.
Here are the approaches I used so far:
Traditional procedural approach:
enum WidgetType {A,B,C,}
interface IWidget
{
WidgetType GetWidgetType();
}
class WidgetA
{
public WidgetType GetWidgetType() {return WidgetType.A;}
}
class WidgetB
{
public WidgetType GetWidgetType() {return WidgetType.B;}
}
class WidgetC
{
public WidgetType GetWidgetType() {return WidgetType.C;}
}
// new classes have to reuse existing "WidgetType"s
class WidgetC2
{
public WidgetType GetWidgetType() {return WidgetType.C;}
}
class Functions
{
void func1(IWidget widget)
{
switch (widget.GetWidgetType())
{
case WidgetType.A:
...
break;
case WidgetType.A:
...
break;
case WidgetType.A:
...
break;
default:
// hard to add new WidgetTypes (each function has to be augmented)
throw new NotImplementedException();
}
}
// other functions may be added easily
}
Traditional object-oriented approach (Visitor-Pattern):
interface IWidgetVisitor
{
void visit(WidgetA widget);
void visit(WidgetB widget);
void visit(WidgetC widget);
// new widgets can be easily added here
// but all visitors have to be adjusted
}
interface IVisitedWidget
{
void accept(IWidgetVisitor widgetVisitor);
}
class WidgetA : IVisitedWidget
{
public void accept(IWidgetVisitor widgetVisitor){widgetVisitor.visit(this);}
public void doStuffWithWidgetA(){}
}
class WidgetB : IVisitedWidget
{
public void accept(IWidgetVisitor widgetVisitor){widgetVisitor.visit(this);}
public void doStuffWithWidgetB(){}
}
class WidgetC : IVisitedWidget
{
public void accept(IWidgetVisitor widgetVisitor){widgetVisitor.visit(this);}
public void doStuffWithWidgetB(){}
}
class SampleWidgetVisitor : IWidgetVisitor
{
public void visit(WidgetA widget){ widget.doStuffWithWidgetA(); }
public void visit(WidgetB widget){ widget.doStuffWithWidgetB(); }
public void visit(WidgetC widget){ widget.doStuffWithWidgetC(); }
}
simple interface approach:
IWidget
{
void DoThis();
void DoThat();
// if we want to add
// void DoOtherStuff();
// we have to change each class
}
WidgetA : IWidget
{
public void DoThis(){ doThisForWidgetA();}
public void DoThat(){ doThatForWidgetA();}
}
WidgetB : IWidget
{
public void DoThis(){ doThisForWidgetB();}
public void DoThat(){ doThatForWidgetB();}
}
WidgetC : IWidget
{
public void DoThis(){ doThisForWidgetC();}
public void DoThat(){ doThatForWidgetC();}
}
It really comes down to where you see the code being most volatile. I suppose I would go the route of having a base class that the Widgets derive from with each function marked virtual so adding a new function doesn't require that all deriving classes provide an implementation and your code won't fail if you call the function on a concrete class that hasn't provided a Widget specific implementation.
I'm facing a similar problem - essentially the issue here is that of multiple dispatch, which is not well-supported in single-dispatch OO languages.
The compromise I have come to is an extensible variation on your Procedural example.
It uses a Mediator (or Coordinator) with a dictionary to register and resolve the actions that should occur between two objects. In the following code example, I am using the problem of collisions between two objects.
The basic structures are:
enum CollisionGroup { Bullet, Tree, Player }
interface ICollider
{
CollisionGroup Group { get; }
}
The Mediator object is defined as follows:
class CollisionResolver
{
Dictionary<Tuple<CollisionGroup, CollisionGroup>, Action<ICollider, ICollider>> lookup
= new Dictionary<Tuple<CollisionGroup, CollisionGroup>, Action<ICollider, ICollider>>();
public void Register(CollisionGroup a, CollisionGroup b, Action<ICollider, ICollider> action)
{
lookup[Tuple.Create(a, b)] = action;
}
public void Resolve(ICollider a, ICollider b)
{
Action<ICollider, ICollider> action;
if (!lookup.TryGetValue(Tuple.Create(a.Group, b.Group), out action))
action = (c1, c2) => Console.WriteLine("Nothing happened..!");
action(a, b);
}
}
Yuck! It doesn't look that nice but that is mainly due to the generic types and lack of supporting objects. I haven't made any for this example because that would introduce too much complexity for the scope of this answer.
The object is used like so:
var mediator = new CollisionResolver();
mediator.Register(CollisionGroup.Bullet, CollisionGroup.Player,
(b, p) => Console.WriteLine("A bullet hit {0} and it did not end well", p));
mediator.Register(CollisionGroup.Player, CollisionGroup.Tree,
(p, t) => Console.WriteLine("{0} ran into a tree. Ouch", p));
mediator.Register(CollisionGroup.Player, CollisionGroup.Player,
(p1, p2) => Console.WriteLine("{0} and {1} hi-fived! Yeah! Awesome!", p1, p2));
var jeffrey = new Player("Jeffrey");
var cuthbert = new Player("Cuthbert");
var bullet = new Bullet();
var tree = new Tree();
mediator.Resolve(jeffrey, cuthbert); // Jeffrey and Cuthbert hi-fived! Yeah! Awesome!
mediator.Resolve(jeffrey, tree); // Jeffrey ran into a tree. Ouch
mediator.Resolve(bullet, cuthbert); // A bullet hit Cuthbert and it did not end well
mediator.Resolve(bullet, tree); // Nothing happened..!
This approach is the most extensible I can find. To add a new reaction or a new type, all that is needed is a new enum member and a call to the .Register() method.
Points for expansion on the above approach:
A generic DispatchMediator<TType, TEnum> is trivially implemented
Similarly, the Tuple<T, T> and Action<T, T> types can be condensed to accept a single type parameter
You could even go further and change the ICollider interface to a generic one if you want to reuse the pattern in several places
The use of extensible enums solves another issue of extensibility (adding a new type)
I have a handful of static "shape" classes that I am using in my program, and since each of the static classes needs to perform the same kind of operations, I'm wondering if there's a way to genericize the method call. If the classes weren't static, I'd simply use an interface.
Here's the gist of my situation:
public static Triangle
{
public int getNumVerts()
{
return 3;
}
public bool isColliding()
{
return Triangle Collision Code Here
}
}
public static Square
{
public int getNumVerts()
{
return 4;
}
public bool isColliding()
{
return Square Collision Code Here
}
}
What I'd prefer to do is simply call Shape.getNumVerts(), instead of my current switch statement:
switch (ShapeType)
{
case ShapeType.Triangle:
Triangle.GetNumVerts();
case ShapeType.Square:
Square.GetNumVerts();
}
I could simply use polymorphism if I used singletons instead of static classes, but singletons are to be avoided, and I'd need to pass a ton of references around so that I could do processing, as needed, on the individual shapes.
Is there a way to group these static classes, or is the switch statement as good as it's going to get?
It's not clear if you need separate Triangle and Square classes. You could eliminate them and have only Shape class with methods accepting ShapeType argument. But it also comes withswitch actually.
public static class Shape
{
public static int GetNumVerts(ShapeType type)
{
switch (type)
{
case ShapeType.Triangle:return 3;
case ShapeType.Square:return 4;
//...
}
}
}
As for switch, I guess it's quite common and normal to use it this way.
Yet you may have separate Triangle and Square classes, and have your switch within Shape.GetNumVerts method. It will let you call Shape.GetNumVerts(ShapeType.Triangle);, i.e. switch is encapsulated within Shape class and used only once there.
public static class Shape
{
public static int GetNumVerts(ShapeType type)
{
switch (type)
{
case ShapeType.Triangle:return Triangle.GetNumVerts();
case ShapeType.Square:return Square.GetNumVerts();
//...
}
}
}
UPDATED I've updated the example to better illustrate my problem. I realised it was missing one specific point - namely the fact that the CreateLabel() method always takes a label type so the factory can decide what type of label to create. Thing is, it might need to obtain more or less information depending on what type of label it wants to return.
I have a factory class that returns objects representing labels to be sent to a printer.
The factory class looks like this:
public class LargeLabel : ILabel
{
public string TrackingReference { get; private set; }
public LargeLabel(string trackingReference)
{
TrackingReference = trackingReference;
}
}
public class SmallLabel : ILabel
{
public string TrackingReference { get; private set; }
public SmallLabel(string trackingReference)
{
TrackingReference = trackingReference;
}
}
public class LabelFactory
{
public ILabel CreateLabel(LabelType labelType, string trackingReference)
{
switch (labelType)
{
case LabelType.Small:
return new SmallLabel(trackingReference);
case LabelType.Large:
return new LargeLabel(trackingReference);
}
}
}
Say that I create a new label type, called CustomLabel. I want to return this from the factory, but it needs some additional data:
public class CustomLabel : ILabel
{
public string TrackingReference { get; private set; }
public string CustomText { get; private set; }
public CustomLabel(string trackingReference, string customText)
{
TrackingReference = trackingReference;
CustomText = customText;
}
}
This means my factory method has to change:
public class LabelFactory
{
public ILabel CreateLabel(LabelType labelType, string trackingReference, string customText)
{
switch (labelType)
{
case LabelType.Small:
return new SmallLabel(trackingReference);
case LabelType.Large:
return new LargeLabel(trackingReference);
case LabelType.Custom:
return new CustomLabel(trackingReference, customText);
}
}
}
I don't like this because the factory now needs to cater for the lowest common denominator, but at the same time the CustomLabel class needs to get a custom text value. I could provide the additional factory method as an override, but I want to enforce the fact that the CustomLabel needs the value, otherwise it'll only ever be given empty strings.
What is the correct way to implement this scenario?
Well, how do you want to call the factory method?
Concentrate on how you want to be able to use your API, and the implementation will usually make itself fairly clear. This is made even easier if you write the desired results of your API as unit tests.
An overload may well be the right thing to do here, but it really depends on how you want to use the factory.
How about just using the Factory method to decide what label you need?
public class LabelFactory {
public ILabel CreateLabel(string trackingReference, string customText) {
return new CustomLabel(trackingReference, customText);
}
public ILabel CreateLabel(String trackingReference) {
return new BasicLabel(trackingReference);
}
}
Your factory still needs to know about each type (although with an interface you can implement dynamic loading) but there is very little that the client needs to know - according to what data is provided, the factory generates the correct implementation.
This is a simplistic solution to the simple problem you described. I assume the question is an oversimplification of a more complex problem but without knowing what your real problem is, I'd rather not design an over complex solution.
This is probably an indication that a factory pattern isn't the best for you. If you do either need or wish to stick with it, though, I would suggest creating initialization classes/structs that can be passed into the factory, rather than the string. Whether you want to do it with various subclasses of a basic information class (basically creating an initialization class hierarchy that mimics that of your label classes) or one class that contains all of the information is up to you.
You should try to use a configuration class and pass an instance of that to the factory. The configuration classes would build a hierarchy, where a special configuration class would exist for each result you expect from the factory. Each configuration class captures the specific properties of the factory result.
For the example you've given I'd write a BasicLabelConfiguration and a CustomLabelConfiguration derived from it. The BasicLabelConfiguration captures the tracking reference, while the CustomLabelConfiguration captures the custom text.
Finally the factory makes a decision based on the type of the passed configuration object.
Here's an example of the code:
public class BasicLabelConfiguration
{
public BasicLabelConfiguration()
{
}
public string TrackingReference { get; set; }
}
public class CustomLabelConfiguration : BasicLabelConfiguration
{
public CustomLabelConfiguration()
{
}
public string CustomText { get; set; }
}
public class LabelFactory
{
public ILabel CreateLabel(BasicLabelConfiguration configuration)
{
// Possibly make decision from configuration
CustomLabelConfiguration clc = configuration as CustomLabelConfiguration;
if (clc != null)
{
return new CustomLabel(clc.TrackingReference, clc.CustomText);
}
else
{
return new BasicLabel(configuration.TrackingReference);
}
}
}
Finally you'd use the factory like this:
// Create basic label
ILabel label = factory.CreateLabel(new BasicLabelConfiguration
{
TrackingReference = "the reference"
});
or
// Create basic label
ILabel label = factory.CreateLabel(new CustomLabelConfiguration
{
TrackingReference = "the reference",
CustomText = "The custom text"
});
Without further information it's pretty hard to give any advice, but assuming that the factory pattern is what you actually need you could try the following approach:
Pack the needed arguments in some kind of property map (e.g. map of string to string) and pass that as an argument to the factory's create method. Use well-known tags as keys in the map, allowing the specialized factories to extract and interpret the mapped values to their own liking.
This will at least allow you to maintain a single factory interface for the time being, and postpone dealing with architectural issues if (or when) you notice that the factory pattern isn't the correct one here.
(Oh, and if you really want to use the factory pattern here I strongly suggest you make it pluggable to avoid having to modify the factory for each new label type).
You are trying to force the pattern into a scenario in which it does not fit. I would suggest giving up on that particular pattern and focus instead of making the simplest solution possible.
I think in this case I would just have one class, Label, that has a text field for custom text that is normally null/empty but which one can set if the label needs to be custom. It is simple, self-explanatory and will not give your maintenance programmers any nightmares.
public class Label
{
public Label(string trackingReference) : this(trackingReference, string.Empty)
{
}
public Label(string trackingReference, string customText)
{
CustomText = customText;
}
public string CustomText ( get; private set; }
public bool IsCustom
{
get
{
return !string.IsNullOrEmpty(CustomText);
}
}
}
ANSWER UPDATED FOLLOWING UPDATE OF THE QUESTION - SEE BELOW
I still think you're right to be using the Factory pattern, and correct in overloading the CreateLabel method; but I think in passing the LabelType to the CreateLabel method, you're missing the point of using the Factory pattern.
Key point: the entire purpose of the Factory pattern is to encapsulate the logic which chooses which concrete subclass to instantiate and return. The calling code should not be telling the Factory which type to instantiate. The benefit is that the code which calls the Factory is therefore shielded from changes to that logic in the future, and also from the addition of new concrete subclasses to the factory. All your calling code need depend on is the Factory, and the Interface type returned from CreateLabel.
The logic in your code at the point where you call the Factory must currently look something like this pseudocode...
// Need to create a label now
ILabel label;
if(we need to create a small label)
{
label = factory.CreateLabel(LabelType.SmallLabel, "ref1");
}
else if(we need to create a large label)
{
label = factory.CreateLabel(LabelType.LargeLabel, "ref1");
}
else if(we need to create a custom label)
{
label = factory.CreateLabel(LabelType.CustomLabel, "ref1", "Custom text")
}
...so you're explicitly telling the Factory what to create. This is bad, because every time a new label type is added to the system, you'll need to...
Change the factory code to deal with the new LabelType value
Go and add a new else-if to everywhere that the factory's called
However, if you move the logic that chooses the LabelType value into your factory, you avoid this. The logic is encapsulated in the factory along with everything else. If a new type of label is added to your system, you only need to change the Factory. All existing code calling the Factory remains the same, no breaking changes.
What is the piece of data that your current calling code uses to decide whether a big label or small label is needed? That piece of data should be passed to the factory's CreateLabel() methods.
Your Factory and label classes could look like this...
// Unchanged
public class BasicLabel: ILabel
{
public LabelSize Size {get; private set}
public string TrackingReference { get; private set; }
public SmallLabel(LabelSize size, string trackingReference)
{
Size = size;
TrackingReference = trackingReference;
}
}
// ADDED THE NULL OR EMPTY CHECK
public class CustomLabel : ILabel
{
public string TrackingReference { get; private set; }
public string CustomText { get; private set; }
public CustomLabel(string trackingReference, string customText)
{
TrackingReference = trackingReference;
if(customText.IsNullOrEmpty()){
throw new SomeException();
}
CustomText = customText;
}
}
public class LabelFactory
{
public ILabel CreateLabel(string trackingReference, LabelSize labelSize)
{
return new BasicLabel(labelSize, trackingReference);
}
public ILabel CreateLabel(string trackingReference, string customText)
{
return new CustomLabel(trackingReference, customText);
}
}
I hope this is helpful.
From reading your question it sounds like your UI collects the information and then uses the factory to create the appropriate label. We use a different approach in the CAD/CAM application I develop.
During startup my applications uses the factory method to create a master list of labels.
Some of my labels have initialization parameters because they are variants of each other. For example we have three type of flat part labels. While others have parameters that are user defined or not known at setup.
In the first case the initialization is handled within the factory method. So I create three instances of FlatPartLabel passing in the needed parameters.
In the second case Label interface has a configure option. This is called by the label printer dialog to populate a setup panel. In your case this is where the tracking reference and CustomText would be passed in.
My label interface also returns a unique ID for each Label type. If I had a specific command to deal with that type of label then I would traverse the list of labels in my application find which one matches the ID, cast it to the specific type of label, and then configure it. We do this when user want to print one label only for a specific flat part.
Doing this means you can be arbitrary complex in the parameters your labels need and not burden your Factory with unessential parameters.