Why objects are orphan, when creator exist - c#

Consider following code
public class City
{
public string Name { get { return "New York"; } }
Building empEstate;
Building nyTimes;
public void Init()
{
// I hate passing "this" to all object
empEstate = new EmpEstate(this);
setSomeProperty(empEstate);
// any one can create new object of some other city
// and pass to the building
nyTimes = new NYTimes(this);
...
other = new OtherBuildings(this)
}
public void PrintAddresses()
{
empEstate.Print();
nyTimes.Print();
...
other.Print();
}
}
public abstract class Building {
City _city;
public Building(City city){
this._city = city;
}
public abstract string Name { get;}
public void Print(){
Console.WriteLine(this.Name);
Console.Write(",");
Console.WriteLine(this._city.Name);
}
}
First thing I want better solution to this approach. Print is just an example. Actually each building object raise some event to City object. I don't want to add handler to each building as there could be several buildings in city. Also I do not want to add each of them into list, as it is two task for each building (one initialization and second add to list, one forget to add to list when writing new building). For this, I want caller to be automatically available to callee, like Parent property of control (though it was added to this.Controls)
Using memory, can we know who is the parent of current object. How does GC knows that object is not being referenced (including creator). Can't we create a method (safe or unsafe) using memory to identify the caller object. I see we can use StackTrace to see the call hirarchy, can we intercept here when a new object is being created.

Building factory on city solved my problem of passing this to each object
public interface ICity
{
string Name { get; }
}
public abstract class City : ICity
{
public T CreateBuilding<T>()
{
T buildingInstance = Activator.CreateInstance<T>();
((IBuilding)buildingInstance).SetCity(this);
return buildingInstance;
}
public abstract string Name { get; }
}
interface IBuilding
{
ICity City { get; }
void SetCity(ICity city);
}
public abstract class Building : IBuilding
{
private ICity _city;
public ICity City { get { return _city; } }
public void IBuilding.SetCity(ICity city)
{
this._city = city;
}
public abstract string Name { get; }
public void Print()
{
Console.WriteLine(this.Name);
Console.Write(",");
Console.WriteLine(this._city.Name);
}
}
public class EmpEstate : Building
{
public override string Name { get { return "Emp State"; } }
}
public class NYTimes : Building
{
public override string Name { get { return "NY Times"; } }
}
public class NewYorkCity : City
{
public override string Name { get { return "New York"; } }
EmpEstate empEstate;
NYTimes nyTimes;
public void Init()
{
// Now I dont need to pass this
empEstate = this.CreateBuilding<EmpEstate>();
setSomeProperty(empEstate);
// now any one cannot create building in new your and
// say it belongs to Philedelphia :)
nyTimes = this.CreateBuilding<NYTimes>();
}
public void PrintAddresses()
{
empEstate.Print();
nyTimes.Print();
}
}
Problem was there were several classes already created and for new functionality we needed the creator object in the base class of Building Object. We did not wanted to modify the constructor of each class and pass this object to each. And City class (in example) was basically code on plugin side, so allowing them to pass city (if plugin developer pass wrong city) may disturb the functionality of entire app. So modifying the plugin base solved my purpose. Suggestions are welcome.

There is no logical "owner" of an object. Inspecting the stack trace is... not usually ideal. By comparison to Parent, that is not very different to your existing approach - merely that is set via methods/properties rather than in the constructor.
If the city is only necessary for the context of methods like Print, why not pass it in as a parameter, i.e. nyTimes.Print(this) etc. If you might need other values, rather than taking lots of parameters, consider using some kind of context object that has a city - i.e.
class PrintContext {
public City City {get;private set;}
// other stuff...
public PrintContext(City city/*, other stuff...*/) {
City = city;
}
}

I think you are misusing the terms parent and creator. The object that created the instance has no special relationship with the instance (e.g. factories create objects, but do not maintain references to them), so, in general, there is no way to find out who or what created a concrete instance.
In the same sense, parent has no meaning on a general object. We can somehow infer that the Form is parent to the TextBox, but that is not a special relationship. It this case it just means that the TextBox is in the form's Contols collection, and that it's Parent is set to the Form.
You are right that this could potentially lead to inconsistencies (Form1 thinks that TextBox is it's child, but the TextBox thinks that it's Parent is Form2), but I do not know of, and don't think there is a better solution of this kind of relationship than the Children collection / Parent reference.

Picking a few of your many questions:
I hate passing this
Why? You are telling the building which city it belongs to. How else could you do this. I see that as a common idiom for wiring objects together.
Also I do not want to add each of them into list, as it is two task
for each building (one initialization and second add to list, one
forget to add to list when writing new building).
I'm not clear what list you want to add them to, but your concern about "forgetting" is overcome if you do the work in the base constructor:
public Building(City city){
this._city = city;
// add the building to the list here - nothing to "forget"
}
As for GC, once a creator has created something there is no relationship between them unless you choose to retain a reference. You have done that with
empEstate = new EmpEstate(this);
so as long as the City is not a candidate for garbage collectio then the EmpState won't be either.

Related

Making collection items read only

I have a business entities as below,
class Class1
{
List<Class2> classes = new List<Class2>();
public IEnumerable<Class2> Classes { get { return classes.AsEnumrable(); }
public void AddClass(Class2 cls)
{
classes.Add(cls);
}
}
class Class2
{
public string Property { get; set; }
}
My business logic requires that once a Class2 instance is added using the AddClass method to the top of the Classes list in Class1, no one should be able to edit the properties of the Class2 instances added previously to the list, only the last item in the list could be edited. How do I do this?
I have tried IReadOnlyList, but it appears that it is concerned with making the list structure itself uneditable without preventing the edit of its items' content.
It's not a container's job to dictate the behavior of its items. A container is just that - an object that contains other objects. An IReadOnlyList is a container whose items cannot be modified. But the items within it are jsut Class2 instances - there's nothing that the container can do to prevent them from being edited.
Consider this:
myReadOnlyCollection[0].Property = "blah";
var firstItem = myReadOnlyCollection[0];
firstItem.Property = "blah";
Should this be legal in your scenario? What's the difference between the two? firstItem is simply an instance of Class2 that has no idea it was once inside a read-only collection.
What you need is for Class2 itself to be immutable. That's up to the class, not the container. Read up on immutability, which is an important concept to grasp, and implement Class2 accordingly. If you need a regular, mutable Class2 to change its behavior, perhaps add a ToImmutable() method to it which returns a different item, without a setter.
Why are you exposing the IReadOnlyCollection. Once you have exposed the objects, the objects themselves have to be immutable.
Why not just expose the only object that you want to expose?
private IEnumerable<Class2> Classes { get { return classes; }
public Class2 Class2Instance { get { return classes.Last(); } }
I can only see three options. One is to alter Class2 to make it lockable and then lock it once it's added to your list...
class Class1 {
List<Class2> classes = new List<Class2>();
public IEnumerable<Class2> Classes {
get { return classes.AsEnumrable();
}
public void AddClass(Class2 cls) {
cls.Lock();
classes.Add(cls);
}
}
class Class2 {
private string _property;
private bool _locked;
public string Property {
get { return _property; }
set {
if(_locked) throw new AccessViolationException();
_property = value;
}
}
public void Lock() {
_locked = true;
}
}
Another option is to only return the values of the list objects instead of the objects themselves...
class Class1 {
List<Class2> classes = new List<Class2>();
public IEnumerable<string> Values {
get { return classes.Select(cls => cls.Property); }
}
public void AddClass(Class2 cls) {
classes.Add(cls);
}
}
In this second method, anything other than a single value and you'll need to either return a tuple. Alternately, you could create a specific container for Class2 that exposes the values as read-only...
class Class2ReadOnly {
private Class2 _master;
public Class2ReadOnly(Class2 master) {
_master = master;
}
public string Property {
get { return _master.Property; }
}
}
class Class1 {
List<Class2ReadOnly> classes = new List<Class2ReadOnly>();
public IEnumerable<Class2ReadOnly> Classes {
get { return classes.AsEnumerable(); }
}
public void AddClass(Class2 cls) {
classes.Add(new Class2ReadOnly(cls));
}
}
I know it is an old problem, however I faced the same issue today.
Background: I want to store data in my application, e.g. users can set their custom objects in the project and the Undo-redo mechanism must be adapted to handle batched data storing.
My approach:
I created some interfaces, and I made a wrapper for the collection I don't want the users to modify.
public class Repository : IRepository
{
// These items still can be changed via Items[0].CustomProperty = "asd"
public readonly List<CustomItem> Items { get; }
private readonly List<CustomItem> m_Originaltems;
//However, when I create RepositoryObject, I create a shadow copy of the Items collection
public Repository(List<CustomItem> items)
{
items.ForEach((item) =>
{
// By cloning an item you can make sure that any change to it can be easily discarded
Items.Add((CustomItem)item.Clone());
});
// As a private field we can manage the original collection without taking into account any unintended modification
m_OriginalItems = items;
}
// Adding a new item works with the original collection
public void AddItem(CustomItem item)
{
m_OriginalItems.Add(item);
}
// Of course you have to implement all the necessary methods you want to use (e.g. Replace, Remove, Insert and so on)
}
Pros:
Using this approach you basically just wraps the collection into a custom object. The only thing you expect from the user side is to have ICloneable interface implemented.
If you want, you can make your wrapper generic as well, and give a constraint like where T : ICloneable
Cons:
If you add new items, you won't know about them by checking the Items property. A workaround can be done by creating a copy of the collection whenever Items.get() is called. It is up to you and your requirements.
I meant something like this:
public class Repository : IRepository
{
public List<CustomItem> Items => m_OriginalItems.Select(item => (CustomItem)item.Clone()).ToList();
private readonly List<CustomItem> m_Originaltems;
public Repository(List<CustomItem> items)
{
m_OriginalItems = items;
}
public void AddItem(CustomItem item)
{
m_OriginalItems.Add(item);
}
// Of course you still have to implement all the necessary methods you want to use (e.g. Replace, Count, and so on)
}
As other said, it is not the collections job to dictate if (and how) you access it's elements. I do see ways around this:
Exceptions & references:
Modify Class2 so it can take a reference to Class1. If the reference is set, throw excetpions on all setters. Modify Class1.AddClass to set that property.
A softer version of this would be a "read only" property on Class2, that all other code has to check.
Readonly Properties & Constructors:
Just always give Class2 readonly properties (private set). If you want to define the property values, you have to do that in the constructor (which has proper Arguments). This pattern is used heavily by the Exception classes.
Inheritance Shenanigans:
Make Multiple Class2 versions in an inheritance chain, so that that Class2Writebale can be cast to a Class2ReadOnly.
Accept the wrong Y:
You might have stuck yourself into a XY problem: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem
If so go a step back to fix it.

C# Access to subclass Proprieties from base class instance

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());
}

Accessing Non Static Method from another page

I have this in a toggle switch event
LevelPage.change_color() = this.ChangeColorToggle.IsOn;
I am pulling a method with the following code from another page, named LevelPage
Moving_Ellipse.Fill = new SolidColorBrush(Colors.Black);
I want the toggle switch even handler to access the method, but it would say that it needs an object for a non-static method. I am pretty new to this stuff, can anyone help me?
Static vs. Instance
class Human {
public static readonly string SpeciesName = "Homo sapiens";
private string Name { get; set; }
}
Static means belonging to a class, intrinsically. For instance, the SpeciesName of Human is "Homo sapiens". This contrasts with the non-static (or instance) property Name. A human, an instance of the Human class, can have a name. An instance of class Human with name Bob makes sense; a Human class with a static Name of Bob would be... interesting.
How to pass state between pages in C# UWP
2 recommended options: Reference
Pass data when changing from one page to another via Frame.Navigate().
Store your data statically for global access.
Personally, I prefer the second option. I usually have an object called Model that holds all of my application's persistent state. I store my only instance of Model as a static property of the App class.
For example, let's say on page1 the user must choose red or blue. Page2 will be that color. So the code would be something like:
class App : Application {
public static Model GlobalModel { get; set; }
//...
}
class Model {
public Color UserSelectedColor { get; set; }
}
class Page1 {
//...
private void StoreSelectedColor(Color selectedColor) {
App.GlobalModel.UserSelectedColor = selectedColor;
}
//...
}
class Page2 {
//...
private Color GetSelectedColor() {
return App.GlobalModel.UserSelectedColor;
}
//...
}

MonoState, Singleton, or Derived Forms: Best approach for CRUD app?

I have a fairly large CRUD WinForm app that has numerous objects. Person, Enrollment, Plan, CaseNote etc. There are over 30 forms that make up the app with the UI broken down logically. Member, Enrollments, Plans, CaseNotes, etc.
I am trying to figure out how I can create my Person Object after searching on the Search Form and pass THE object to the next requested form. Whatever that may be, let's say Demographics. The short of it is that I need the Person object to be available throughout the App and there can only be one.
Now I have ZERO exposure to Design Patterns but I am trying. I have read http://www.switchonthecode.com/tutorials/csharp-tutorial-singleton-pattern and http://www.yoda.arachsys.com/csharp/singleton.html but I want to make sure I understand correctly how to apply this to my situation.
First, the examples state that you are accessing a reference, correct? Am I mistaken or would I need to access the value?
Second, is there anything else that I need to do to make this Globally available? Do I just declare a instance on each form but through this Singleton Pattern so as to not have more then one?
Thanks
EDIT 1
To clarify, All objects are child objects of Person. Also, As the Search Page eludes to; the users can select a different currentPerson. But they can only interact with ONE Person at a time.
Lastly, as I stated I am an infant in this and if I should be considering something else, a different approach please say so and if you'd be so kind as to offer some explanation as to why, I'd be very grateful.
EDIT 2
Based on Medicine Man's comment I thought I wauld clarify.
First, Thank you to everyone who has contributed so far.
Second, I don't know the first thing about design patterns and I certainly don't have the foggiest if a certain one is needed in my current situation.
If someone has a better, simpler, or ,in your opinion, a more fitting method of passing a Data Object from FORM to FORM to FORM then PLEASE tell.
In the end I just need a way of tracking the information as my users go from place to place.
Thank You
First, the examples state that you are accessing a reference, correct? Am I mistaken or would I need to access the value?
Your class that you are accessing is a reference to a single class in memory. For example, say your class is:
public class Person { ... }
If you have a singleton of that, you'll have a single "Person" saved in memory, with a shared reference to that one person in the singleton. When you access your single person, you'll be working with that reference, which is probably what you want. Any changes to the person will change it everywhere.
Second, is there anything else that I need to do to make this Globally available? Do I just declare a instance on each form but through this Singleton Pattern so as to not have more then one?
Singletons are used to basically enforce that every time you use the object, it's the same object (each use is a separate reference to the one, single object in memory). You can just grab the singleton anywhere you need it, and it'll just work.
You can use the Singleton pattern to assure that only one instance is ever created.
However, the jury is still out (at least in my mind) on whether this is a good decision. There's plenty of reading on SO and other places about this.
I would approach this from a different angle. I'd make all of my forms take in a Person instance in the constructor. That way, each form is only ever worried about it's instance of Person.
You could do this by creating a new class that inherits from Form and has a field/property/constructor for your Person. Then, any form that uses Person can inherit from your new class.
You would, of course, have to manage the creation of your Person object. You could even do this with a singleton. However, the benefit is that each form doesn't have to know how to create a Person or who created the Person. That way, if you choose to move away from the Singleton pattern, you wouldn't have to go change all of your references to your singleton instance.
EDIT:
Here's some code to demonstrate this. It took me a while to get the designer to play nice. I had to add an empty private constructor in PersonForm to get the designer to not throw an error.
Program.cs
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyDerivedForm(new Person { Name = "Hello World!" }));
}
}
Person.cs
public class Person
{
public virtual string Name { get; set; }
}
PersonForm.cs
using System;
using System.Windows.Forms;
public class PersonForm : Form
{
private readonly Person myPerson;
protected virtual Person MyPerson
{
get
{
return this.myPerson;
}
}
private PersonForm()
{
}
public PersonForm(Person person)
{
this.myPerson = person;
}
}
MyDerivedForm.cs (add a label named label1)
public partial class MyDerivedForm : SingletonMadness.PersonForm
{
public MyDerivedForm(Person person)
: base(person)
{
InitializeComponent();
}
private void MyDerivedForm_Load(object sender, EventArgs e)
{
label1.Text = this.MyPerson.Name;
}
}
You could do something like this:
public static class PersonController
{
private static Person _Person;
public static Person GetPerson()
{
if (_Person == null)
_Person = new Person();
return _Person;
}
}
This will ensure there is only one person object. You will be getting a reference to the _Person object, not a copy, so any changes will be to the single object you're expecting.
As Reed says, singletons enforce that the same object is used throughout the application. However, from your question it doesn't look to me like you do have the same instance of the person class available throughout the entire application, since there is the "search form" which looks like it allows you to change the currently selected person.
In this case your singleton may need to be a container class that holds the current context of the application and which person is currently selected. This may be something like:
public class Context
{
private static Context _instance;
public static Context Instance
{
get
{
if (_instance == null)
{
_instance = new Context();
}
return _instance;
}
}
public Person CurrentlySelectedPerson { get; set; }
private Context() { }
}
(Note that this isn't an ideal singleton pattern since it isn't thread safe...)
Then the search form would set the currently selected person with:
Context.Instance.CurrentlySelectedPerson = personSelectedInForm;
And the demographic from can use it like:
//Get the demographics for the current person
ShowDemographics(Context.Instance.CurrentlySelectedPerson);
You could also use the monostate pattern with your Personclass.
public class Person
{
public Guid Id { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
}
Build a monostate object for Person.
public class CurrentPerson
{
public static Person Person { get; set; }
public Guid Id
{
get { return CurrentPerson.Person.Id; }
set { CurrentPerson.Person.Id = value; }
}
public String FirstName
{
get { return CurrentPerson.Person.FirstName; }
set { CurrentPerson.Person.FirstName = value; }
}
public String LastName
{
get { return CurrentPerson.Person.LastName; }
set { CurrentPerson.Person.LastName = value; }
}
}
Now you can initialize the monostate.
CurrentPerson.Person = GetPersonByUserInput();
And then use CurrentPerson instances throughout the code and they will all access a common shared state.
CurrentPerson currentPerson = new CurrentPerson();

Factory class knows too much

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.

Categories