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());
}
Related
I have a class Step
public class TrainingStep
{
private List<Part> parts;
public Part currentPart;
public void AddPart(Part part)
{
parts.Add(part);
}
///a lot of public methods which are called from one layer above Step( a class containing Step list)
}
In this code the Part doesn't know anything about Step.
The currentPart is changing very often
and I want all of parts to know which is the current now
To achieve this I considered to add step as a parameter for Part class constructor, in order every part knows to which Step it belongs.
Something like this
public Part(Step step, ...)
{
this.step = step;
}
But the problem of such kind of solution is that I can access every public method in Step class from Part using the reference which I've passed via constructor.
But I want to access only currentPart field from Part.
How can I achieve this?
You might define a Func<Part> which returns your currentPart and pass this delegate to your parts.
public class TrainingStep
{
private List<Part> parts;
public Part currentPart;
private Func<Part> getCurrentPartFunc = () => currentPart;
public void AddPart(Part part)
{
part.GetCurrentpart = getCurrentPartFunc;
parts.Add(part);
}
}
class Part
{
public Func<Part> GetCurrentPart {get; set;}
}
I'm playing with some application and doing a little refactoring in order to make it more flexible. As I expected, a lot of problems arose.
For example i'm trying to find optimal way to delete items from collections in Spaceship class
class Spaceship{
List<Weapon> Weapons {get;set;}
List<Shield> Shields {get;set;}
public void RemoveEquipment(Equipment item){
switch(item.EquipmentType )
{
case EquipmentType.Weapon:
weapons.Remove(item);
break;
case EquipmentType.Shield:
shields.Remove(item);
break;
}
}
public void AddEquipment(Equipment item){
//works the same way as RemoveEquipment
}
}
class Equipment{
//EquipmentType is enum
EquipmentType Type {get;set;};
}
class Weapon: Equipment{
}
class Shield:Equipment{
}
class AutoCannon:Weapon{
}
class LaserGun:Weapon {
}
Is there a better way? What if I want to delete group of items of the same subtype (e.g. every LaserGun in weapons collection - without using reflection)
And if I want to add a new type of Equipment, the methods responsible for adding/deleting have to be modified (switch/case).
As a rule of thumb, you do not want to expose properties of type List, especially if they are not readonly. I would suggest changing the Weapons and Shields properties to either IEnunerable or at the very least IReadOnlyList - and make them readonly.
Having said that, your Spaceship class can look like this:
// internal is the default access modifier for types, but it's more descriptive to specify it.
internal class Spaceship
{
private List<Equipment> _equipment = new List<Equipment>();
public IEnumerable<Weapon> Weapons {get {return _equipment.OfType<Weapon>();}}
public IEnumerable<Shield> Shields {get {return _equipment.OfType<Shield>();}}
public void RemoveEquipment(Equipment item)
{
_equipment.Remove(item);
}
public void AddEquipment(Equipment item)
{
_equipment.Add(item);
}
}
And then, in order to remove all equipments of a specific type, you can do something like this:
public void RemoveEquipment<T>() where T : Equipment
{
_equipment.RemoveAll(e => e is T);
}
You can also add a bunch of equipment at the same time:
public void AddEquipment(IEnumerable<Equipment> items)
{
_equipment.AddRange(items);
}
Note that there are no more cumbersome switch statements and almost nothing involving the specific type of the equipment - except when you explicitly need shields and weapons.
The main benefit, of course, is that when adding a new type of equipment, you don't need to change your Spaceship class to support it (Unless, of course, you want to have a property specialized for that specific type of equipment like Weapons or Shields).
Forgive me because I know my wording is terrible. I'll just give an example.
public class MainClass{
public int someVariable;
public List<HasAClass> cList = new List<HasAClass>();
addHasAClass(HasAClass c){
cList.Add(c);
}
}
public class HasAClass{
public HasAClass(){
//Modify someVariable in some way????
}
}
public class HasASubClass : HasAClass{
public ComposedClass(){
//Modify someVariable in some way???
}
}
I having trouble finding the right words for this questions but here is what I am trying to do:
I am creating an aid for an RPG similar to dungeons and dragons. Each character can have a variety of special abilitys which can effect the characters in some way (both negative and positive). I am trying do this with a variety of subclasses which store the pertinent info and get added to the character at varying points in time. What I can't figure out is how to modify the properties of the Character(I called it Main Class in my example) when instances of the HasA class are added to it.
The HasAClass needs a reference to the owning instance, so that it can ask the parent for values and update them when required...
public class HasAClass
{
private MainClass _mainClass;
public HasAClass(MainClass mainClass)
{
_mainClass = mainClass;
_mainClass.someVaraible = 42;
}
}
You then need to pass the owner reference into the constructor of the HasAClass when they are created. If this is not possible at the time of creating the instance then you would instead need to assign it as a property after it has been created. Such as inside the addHasAClass method.
I previously posted this, but I guess it was too verbose and irrelevant. My question is also like this. One poster in the second link said the answer (of why you can't do the code below) was a problem of design, specifically "bad use of inheritance". So I'd like to check this issue again with the experts at StackOverflow and see if this is really an issue of "bad inheritance" - but more importantly, how to fix the design.
Like the poster, I'm also confused about the Factory method and how I can apply it. It seems the factory method is for multiple concrete classes that have the exact same implementation as the abstract base class and do not add their own properties. But, as you will see below, my concrete classes build upon the abstract base class and add extra properties.
The Base Class We Build Upon:
public abstract class FlatScreenTV
{
public string Size { get; set; }
public string ScreenType { get; set; }
}
Extension Class Examples:
public class PhillipsFlatScreenTV : FlatScreenTV
{
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity { get; set; }
}
public class SamsungFlatScreenTV : FlatScreenTV
{
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime { get; set; }
}
Let's say there are more extension classes for more brands of flat screen TVs. And then, let's say we stick them all into a generic List:
public static void Main()
{
List<FlatScreenTV> tvList = new List<FlatScreenTV>();
tvList.Add(new PhillipsFlatScreenTV());
tvList.Add(new SamsungFlatScreenTV());
tvList.Add(new SharpFlatScreenTV());
tvList.Add(new VizioFlatScreenTV());
FlatScreenTV tv = tvList[9]; // Randomly get one TV out of our huge list
}
The Problem:
I want to access the specific properties of whatever 'original' brand TV this variable belongs to. I know the brand because if I call tv.GetType(), it returns the correct 'original' type - not FlatScreenTV. But I need to be able to cast tv from FlatScreenTV back to its original type to be able to access the specific properties of each brand of flat-screen TVs.
Question #1: How can I dynamically cast that, properly - without makeshift hacks and huge if-else chains to brute-guess the 'original' type?
After browsing around similar design issues, most answers are: you can't. Some people say to look at the Factory Pattern, and others say to revise the design using interfaces, but I don't know how to use either to solve this problem.
Question #2: So, how should I design these classes so that I can access the original type's specific properties in the context above?
Question #3: Is this really bad inheritance?
Your design violates the "Liskov Substitution Principle". In other words, the code that deals with items from your list of FlatScreenTV shouldn't know or care what derived type is.
Say your code needs to create a custom remote control GUI. It might be enough to simply know the names and types of the properties of each TV to auto-generate the UI. In which case you could do something like this to expose the custom properties from the base class:
public abstract class FlatScreenTV
{
public FlatScreenTV()
{
CustomProperties = new Dictionary<string,object>();
}
public Dictionary<string,object> CustomProperties { get; private set; }
public string Size { get; set; }
public string ScreenType { get; set; }
}
public class PhillipsFlatScreenTV : FlatScreenTV
{
public PhillipsFlatScreenTV()
{
BackLightIntensity = 0;
}
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity
{
get { return (double)CustomProperties["BackLightIntensity"]; }
set { CustomProperties["BackLightIntensity"] = value; }
}
}
public class SamsungFlatScreenTV : FlatScreenTV
{
public SamsungFlatScreenTV()
{
AutoShutdownTime = 0;
}
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime
{
get { return (int)CustomProperties["AutoShutdownTime"]; }
set { CustomProperties["AutoShutdownTime"] = value; }
}
}
If you really do need to be working directly with the derived types, then you should instead consider moving to a plugin based architecture. For example, you might have a factory method like this:
IRemoteControlGUI GetRemoteControlGUIFor(FlatScreenTV tv)
which would scan your plugins and find the one that knew how to build the UI for the particular type of FlatScreenTV you passed in. This means that for every new FlatScreenTV you add, you also need to create a plugin that knows how to make its remote control GUI.
Factory Pattern would be the best way to go
I can offer a partial answer:
Firstly read up on Liskov's Substitution Principle.
Secondly you are creating objects that inherit from FlatScreenTV, but apparently for no purpose as you want to refer to them by their SubType (SpecificTVType) and not their SuperType (FlatScreenTV) - This is bad use of Inheritance as it is NOT using inheritance lol.
If your code wants to access properties particular to a given type, then you really want this code encapsulated within that type. Otherwise everytime you add a new TV type, all the code that handles the TV list would need to be updated to reflect that.
So you should include a method on FlatScreenTV that does x, and override this in TV's as required.
So basically in your Main method above, instead of thinking I want to be dealing with TVTypeX, you should always refer to the basetype, and let inheritance and method overriding handle the specific behaviour for the subtype you are actually dealing with.
Code eg.
public abstract class FlatScreenTV
{
public virtual void SetOptimumDisplay()
{
//do nothing - base class has no implementation here
}
}
public class PhilipsWD20TV
{
public int BackLightIntensity {get;set;}
public override void SetOptimumDisplay()
{
//Do Something that uses BackLightIntensity
}
}
"the factory method is for multiple concrete classes that have the exact same implementation as the abstract base class [interface] and do not add their own properties."
No, speaking more practical, than theorical, the factory method can provide you with objects of concrete classes, in which the concrete classes, must have some common methods and interfaces, but, also some additional specific attributes.
Sometimes I use a method that creates the same class object every time I called, and I need to call it several times, and sometimes I use a method that create several different class objects, and that maybe be confusing, maybe another question.
And, your further comment about a switch sentence, with many options, when using the factory pattern, you usually provide an identifier for the concrete class / concrete object. This can be a string, an integer, an special type id, or an enumerated type.
You could use an integer / enum ID instead, and use a collection to lookup for the concrete class.
You can still leverage a factory. The point of a factory IMO is to put all the heavy lifting of constructing your various TVs in one place. To say categorically "a factory is for multiple concrete classes that have the exact same implementation as the abstract base class" is forgetting about polymorphism.
There is no law that says you cannot use a factory pattern because the sub classes declare unique properties and methods. But the more you can make use of polymorphism, the more a factory pattern makes sense. Also as a general guideline, IMHO, the more complexity that must go into constructing from the base the better off you are in the long run using a factory because you are "encapsulating change" - that is, constructing concrete classes is likely to change due to differing requirements and inherent construction complexity (a design analysis decision, to be sure) . And that change is in a single class - the factory.
Try this: Define everything in the abstract class and then for a given TV subclass either write concrete-specific code, and for those that don't apply write some standard "I don't do that" code.
Think about all the things your TVs do in generic terms: turn on, turn off, etc. Write a virtual method shell in the base class for all the generic things a TV does - this is a simple example of the template method pattern by the way. Then override these in the concrete classes as appropriate.
There are other things you can do in the base class to make it more fundgeable (that's a technical term meaning "reference subclasses as the base class, but do sub-classy things").
Define delegate methods (very powerful yet under-utilized)
use params[] for dynamic method parameter lists
Make Property delegates
Static methods
Declare Properties and methods "abstract" - forces sub-class implementation, vis-a-vis "virtual"
Hide inherited stuff in the sub class (generally using "new" keyword to communicate that it's on purpose)
If construction parameters are numerous or complex, create a class specifically designed to pass configuration to the factory's build method.
public class TVFactory {
public TV BuildTV(Brands thisKind) {
TV newSet;
switch (thisKind) {
case Brands.Samsung :
Samsung aSamsungTV = new Samsung();
aSamsungTV.BacklightIntensity = double.MinVal;
aSamsungTV.AutoShutdownTime = 45; //oops! I made a magic number. My bad
aSamsungTV.SetAutoShutDownTime = new delegate (newSet.SetASDT);
newSet = aSamsungTV;
break;
. . .
} // switch
}
//more build methods for setting specific parameters
public TV BuildTV (Brands thisKind, string Size) { ... }
// maybe you can pass in a set of properties to exactly control the construction.
// returning a concrete class reference violates the spirit of object oriented programming
public Sony BuildSonyTV (...) {}
public TV BuildTV (Brands thisKind, Dictionary buildParameters) { ... }
}
public class TV {
public string Size { get; set; }
public string ScreenType { get; set; }
public double BackLightIntensity { get; set; }
public int AutoShutdownTime { get; set; }
//define delegates to get/set properties
public delegate int GetAutoShutDownTime ();
public delegate void SetAutoShutDownTime (object obj);
public virtual TurnOn ();
public virtural TurnOff();
// this method implemented by more than one concrete class, so I use that
// as an excuse to declare it in my base.
public virtual SomeSonyPhillipsOnlything () { throw new NotImplementedException("I don't do SonyPhillips stuff"); }
}
public class Samsung : TV {
public Samsung() {
// set the properties, delegates, etc. in the factory
// that way if we ever get new properties we don't open umpteen TV concrete classes
// to add it. We're only altering the TVFactory.
// This demonstrates how a factory isolates code changes for object construction.
}
public override void TurnOn() { // do stuff }
public override void TurnOn() { // do stuff }
public void SamsungUniqueThing () { // do samsung unique stuff }
internal void SetASDT (int i) {
AutoShutDownTime = i;
}
}
// I like enumerations.
// No worries about string gotchas
// we get intellense in Visual Studio
// has a documentation-y quality
enum Brands {
Sony
,Samsung
,Phillips
}
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.