The best way to implement settings in my design

I’m wondering what is the best way to insert customization adapters into an application. In principle, my application is divided into two assemblies: A Coreassembly containing all the business logic and the assembly UserInterfacecontaining the GUI, controller classes (I use the Passive View MVC template deviant) and some auxiliary classes. The assembly core is also used by some other applications .

My application is used by our company to process orders from other companies. The general process is the same for all companies, but here and there there are small deviations characteristic of the client. At the moment, these deviations are embedded directly in the kernel assembly, which smells. I want to separate these features, to integrate them in the best way into one object per client, so I have a central object containing all the client-specific details that I can add to the UserInterface assembly.

I was thinking about using events to achieve this. By adding some events to my main classes, my controller classes could pick up or unsubscribe using these rejections for specific clients.

I can think of two ways of doing this: adding these bindings manually or adding them automatically if deviant methods exist. I am thinking of something similar for the latter:

foreach (Order order in form.SelectedOrders) {
    CustomerExtension customer = customerExtensions[order.Customer];

    if(Exists(customer.StatusChanging(...)) // Pseudo Code!
            OrderManager.StatusChanging += new StatusChangingEventHandler(customer.StatusChanging(...));

    order.SetStatus(newStatus);

    if(Exists(customer.StatusChanging(...)) // Pseudo Code!
            OrderManager.StatusChanging -= new StatusChangingEventHandler(customer.StatusChanging(...));
}

I think I need to use Reflection to achieve this, but how viable is it for operations that need to be done many times?

Or are there better ways to add custom clicks while depriving me of centralizing client-based deviations?

[EDIT] Completely changed the question.

+3
source share
3 answers

, ( , ?). - : ( ) , , ...: -)

// Begin personalization assembly (one of many)-----------------------

/// <summary>
/// Here you could use an attribute to allow clean reflection
/// </summary>
// [CustomerSpecific("Acme")]
public class AcmeCustomization : BaseCustomization
{
    public override void OnStatusChanged()
    {
        base.OnStatusChanged();
        // do what you need to customize
    }
}
// End personalization assembly (one of them)-------------------------

// Begin core assembly -----------------------------------------------
public interface ICustomization
{
    void OnStatusChanged();
}

/// <summary>
/// This class is optional of course, but can be useful
/// </summary>
public class BaseCustomization : ICustomization
{
    public virtual void OnStatusChanged()
    {
        // intentionally empty
    }
}

class CustomizationFactory
{
    public ICustomization GetCustomization(string order)
    {
        // Here you could
        // - hardcode (as you did in your solution)
        // - use reflection (various ways)
        // - use an external mapping file
        // - use MEF (!)
        // and then
        // - do instance caching
        // - whatever...

        // I'm lazy ;-)
        return null;
    }
}

class OrderManager
{
    private ICustomization _customization = null;

    public void SetStatus(string order, int status)
    {
        // Do some work
        this.OnStatusChanged();
        // Do some other work
    }

    protected void OnStatusChanged()
    {
        if (_customization != null)
        {
            _customization.OnStatusChanged();
        }
    }

    public void SetCustomization(ICustomization customization)
    {
        _customization = customization;
    }

    public void ClearCustomization()
    {
        _customization = null;
    }
}
// End core assembly -------------------------------------------------

class Program
{
    static void Main(string[] args)
    {
        CustomizationFactory factory = new CustomizationFactory();
        OrderManager manager = new OrderManager();

        // here I'm just pretending to have "orders"
        var orders = new string[] { 
            "abc",
            "def"
        };

        const int newStatus = 42;

        foreach (var order in orders)
        {
            manager.SetCustomization(factory.GetCustomization(order));
            manager.SetStatus(order, newStatus);
            manager.ClearCustomization();
        }
    }
}

+3

, , ( , ). . - - , :

abstract class SomeBaseClass
{

   public void DoSomething()
   {
       ...
       somethingElse();
       ...
   }

   abstract void somethingElse();

}

public class CompanyA : SomeBaseClass
{
    void somethingElse()
    {
       // do something specific
    }
}

public class CompanyB : SomeBaseClass
{
    void somethingElse()
    {
       // do something specific
    }
}
+1

, , .

, / - . .

The only drawback is that I have to add / remove subscription processing in controller classes manually. For example. my method is SetStatusas follows:

foreach (Job job in form.SelectedJobs) {
    // Subscribe customer-specific methods to events
    switch (job.Customer.Code) {
            case "VNR":
                    jobManager.JobStatusChanged += new JobManager
                        .JobStatusChangedHandler(Vnr.OnStatusChanged);
                    break;
            case "LS":
                    jobManager.JobStatusChanged += new JobManager
                        .JobStatusChangedHandler(Ls.OnStatusChanged);
                    break;
    }

    jobManager.SetStatus(job, status);

    // Unsubscribe customer-specific methods from events
    switch (job.Customer.Code) {
            case "VNR":
                    jobManager.JobStatusChanged -= new JobManager
                        .JobStatusChangedHandler(Vnr.OnStatusChanged);
                    break;
            case "LS":
                    jobManager.JobStatusChanged -= new JobManager
                        .JobStatusChangedHandler(Ls.OnStatusChanged);
                    break;
    }
}

Which is really not very elegant, but it's not so bad.

0
source

Source: https://habr.com/ru/post/1716652/


All Articles