简体   繁体   中英

What's the best design pattern for this problem?

Currently I am trying to implement a system or a way to create types but also get the type name when created.

So say I have actions like these, that can be created by the user of the app:

Blur
Contrast
Sharpen
Diffuse
Invert
...

So how should I extract their name when they are created through the UI. So say you have seperate UI buttons for each. Each time you create one of these, they will have to be named Blur01 , Blur02 , ... These objects will be created in millions.

So currently they have .Name property that has to be set on creation. But also I don't want to duplicate the code to set the names, inside each class.

What design pattern should I use for this?

If you want each type to get it's own, unique incrementers, you're going to have duplicated code. You could avoid this with reflection by saving a static dictionary in a base class with Type and int... something like:

private static Dictionary<Type,int> nameSuffixCounters =
     new Dictionary<Type,int>();

public string CreateName()
{
    Type type = this.GetType();
    return string.Format("{0}{1}",type.Name, this.GetNextAndIncrement(type));
}

private int GetNextAndIncrement(Type type)
{
    int current;
    if (!this.nameSuffixCounters.TryGetValue(type, out current))
    {
        current = 0;
    }
    nameSuffixCounters[type] = ++current;
    return current;
}

Something like this would get rid of the duplicated code, but it's adding some complexity in using reflection in the base class...

Command Pattern ?

Using this pattern would have the advantage of laying the groundwork for undo/redo capability , which it looks like you might need at some point.

Briefly, you could create a interface called "Command" from which subclasses called "Blur", "Sharpen", etc would be derived. Command would define an execute() method that would be implemented by your subclasses as needed:

public interface Command
{
  public void execute();

  public String getName();
}

public class Blur implements Command
{
  // ...

  public Blur(String name)
  {
    // ...
  }

  //...

  public void execute()
  {
    // execute the blur command
  }
}

Many UI toolkits come with support for this pattern - for example Swing. So you may not need to do much to get it working.

I'm not sure why (most) of the answers mention reflection - good ol' polymorphism works just fine for this. Getting the runtime type name is easy - it's just this.GetType().Name .

The only somewhat tricky part is maintaining unique counters per class. That's been discussed before on SO - but I can't find a link ATM. But, the bottom line, is that you can either (ab)use generics or maintain a Dictionary<Type, int> to keep track.

The generic version works because each different type parameter creates a different generic class - so they each have different static counters:

abstract class Command<T> where T : Command<T> {
   private static int counter = 1;
   private static object syncLock = new object();

   protected Command() {
      lock (syncLock) {
         _name = this.GetType().Name + counter++.ToString();
      }
   }

   public string Name { get { return _name; } }
   private string _name;
}

class Blur : Command<Blur> { }

class Sharpen : Command<Sharpen> { }

There's no need to override anything in the derived classes, but you do have to make sure your inherited Command<T> is correct - or you'll share counters. I also used a lock to synchronize access to counter - assuming you'll create instances from more than 1 thread.

If you don't like the generic version, then a Dictionary<Type, int> works just as well.

abstract class Command {
   private static Dictionary<Type, int> counter = new Dictionary<Type, int>();
   private static object syncLock = new object();

   protected Command() {
      Type t = this.GetType();
      lock (syncLock) {
         if (!counter.ContainsKey(t)) {
            counter.Add(t, 0);
         }
         _name = t.Name + counter[t]++.ToString();
      }
   }

   public string Name { get { return _name; } }
   private string _name;
}

class Blur : Command { }
class Sharpen : Command { }

Since you'll be creating "millions" of each, I'd probably profile both and check memory usage. I don't particularly care for the generic approach - since it's easy to screw up and pass the wrong type parameter - but I suspect it's memory usage is a bit better. Also, if you're going to create > int.MaxValue , you'll have to worry about overflow.

All that being said, I'm not sure why you wouldn't just maintain an index addressable collection and reference them by index - like Blur[0] ?

I'm afraid there's no way to do this in one single place.. You will have to explicitly 'type' the class (type) name in each class definition. The reason is that any reflection in the base class will return the base class type, not the concrete type... unless you override the method in each derived class, in which case you might as well hard code the type name as a string const (to avoid the reflection hit) ...

So, what about

public const string TypeName = "MYTypeName";

If it doesn't have to be human readable I would use a GUID as the name of the object and have a base field to indicated the base action that it was created from. Each object can be uniquely identified as (Base Name)-(ID). You could have a human readable Description field but that not used for look up. If you do need to display a GUID a trick that I use is convert from Base 16 to Base 34. Basically from 0123456789ABCDEF to 0123456789ABCDEFGHJKLMNPQRSTUVWXZY. This produces a much shorter string that is easier to display and type in.

Your best bet is to create a property (or function, if you prefer) in the base class that's virtual and provides a sort of base name. Something like..

public virtual string BaseName
{
    get { return GetType().Name; }
}

Your .Name property could stay the same, or change to something like .NameSuffix , and you could combine BaseName and NameSuffix to form a complete name.

In the end, though, this probably isn't the best way to go about this. What is the purpose of naming these objects/actions? It looks to me like you're using a command pattern in image manipulation and you're either setting up a chain of actions to perform, or want to keep a chain of actions to undo. Such a system would be better suited to a linked list structure, which you could display (if necessary) in some sort of graph, showing the action (likely the name of the class, or the BaseName as defined above) and the series in which they would be executed.

As far as your need to use the name to instantiate the objects, I'm not quite sure why. If this is truly necessary, your only two options would be a factory pattern or using reflection on either the name of the class or a custom attribute value (which could also be used for providing the name, if desired). However, if you're going to be instantiating them "in the millions" stay away from reflection .

I guess this is a roundabout way of saying it all depends on how this needs to work. You'll have to provide more concrete and comprehensive information for a correspondingly concrete and comprehensive answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM