Как сказать классу, какие объекты он должен создать? Тип против объекта путаницы :( - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть класс (SetOfRules), который хочет обрабатывать правила (как-то). Задача: создать новый экземпляр этого класса (это легко), а затем добавить правила (определенные в классе Правила и производные классы) к экземпляру.

Проблема 1: Я не хочу создавать экземпляры всех правил и затем передавать их как объекты в Add-метод SetOfRules, но вместо этого я хочу передать список Имен классов (Типов) в Add-метод. Как я могу это сделать? И как тогда синтаксис создания такого объекта внутри SetOfRules?

Проблема 2: Правила класса и производные классы не содержат никаких атрибутов. Это просто наборы методов преобразования. Нужно ли мне когда-либо создавать их экземпляры как объект внутри класса SetOfRules или я могу просто вызывать их как метод статических классов (я не могу использовать статические классы, поскольку использую наследование в классе Rule, чтобы гарантировать, что каждый класс правил реализует методы, которые являются необходимо)

Вот некоторый (псевдо) код, который у меня есть для моей проблемы прямо сейчас:

public class Rule
{
    virtual void transform( myObject ob)
    {
        ...
    }
}

public class SpecificRule1 : Rule
{
    ...
}

public class SpecificRule2 : Rule
{
    ...
}



public class SetOfRules
{
    public AddRules( ???? ListOfRuleTypes)
    {
    }
}

Где-то еще я хочу сделать что-то вроде:

SetOfRules easyRules = new SetOfRules();
easyRules.Add( new ??RuleTypes??[] { "SpecificRule2", "SpecificRule13", "SpecificRule22" });

Спасибо за ваши классные советы!

Ответы [ 3 ]

0 голосов
/ 03 ноября 2018

Похоже, вы хотите класс синглтона с контрактом:

public interface IRule
{
    void Transform(object o);
}
public abstract class SingletonBase<T> where T : SingletonBase<T>, new()
{
    public static T Instance { get; } = new T();
}
public class SpecificRule1 : SingletonBase<SpecificRule1>, IRule
{
    public void Transform(object o) => throw new NotImplementedException();
}
public class SpecificRule2 : SingletonBase<SpecificRule2>, IRule
{
    public void Transform(object o) => throw new NotImplementedException();
}
public class RuleSet : List<IRule>
{
    public void Add<TRule>() where TRule : SingletonBase<TRule>, IRule, new()
    {
        this.Add(SingletonBase<TRule>.Instance);
    }
}

И вы можете добавлять правила различными способами:

var rules = new RuleSet
{
    SpecificRule1.Instance,
    SpecificRule2.Instance,
};

rules = new RuleSet();
rules.Add(SpecificRule1.Instance);
rules.Add<SpecificRule2>();
0 голосов
/ 03 ноября 2018

Пример - правила расчета скидки для позиции заказа:

public class OrderItem
{
    public int ItemId { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }

    public decimal Total => Quantity * Price;
}

Договор (он же интерфейс) на скидку можно определить так:

public interface IDiscountRule
{
    decimal CalculateDiscount(OrderItem item);
}

Теперь давайте реализуем некоторые правила скидок

  • Базовая скидка (2%)
  • Серебряная скидка (5%)
  • Золотая скидка (10%)

Определения классов:

/// <summary>
/// Abstract base class for the discount rules
/// </summary>
public abstract class DiscountRule : IDiscountRule
{
    private readonly int _percent;

    protected DiscountRule(int percent)
    {
        _percent = percent;
    }

    /// <inheritdoc />
    public decimal CalculateDiscount(OrderItem item)
    {
        if (item == null)
        {
            throw new ArgumentNullException(nameof(item));
        }

        decimal discount = item.Total * (decimal) (_percent/100.0);

        return discount;
    }
}


/// <summary>
/// 2% discount
/// </summary>
public class BasicDiscountRule : DiscountRule
{
    public BasicDiscountRule() : base(2)
    {

    }
}

/// <summary>
/// 5% discount
/// </summary>
public class SilverDiscountRule : DiscountRule
{
    public SilverDiscountRule() : base(5)
    {

    }
}

/// <summary>
/// 10% discount
/// </summary>
public class GoldDiscountRule : DiscountRule
{
    public GoldDiscountRule() : base(10)
    {

    }
}

Расчет скидки для позиции заказа с использованием правила:

var item = new OrderItem
{
    ItemId = 1,
    Price = 50,
    Quantity = 2
};

var rule = new SilverDiscountRule();
decimal discount = rule.CalculateDiscount(item);

Теперь давайте создадим составное правило, чтобы применить несколько правил (скидок) к позиции заказа:

/// <summary>
/// To apply multiple discount rules to an order item
/// </summary>
public class CompositeDiscountRule : IDiscountRule
{
    private readonly List<Type> _discountTypes;

    public CompositeDiscountRule()
    {
        _discountTypes = new List<Type>();
    }

    public CompositeDiscountRule(List<Type> discountTypes)
    {
        if (discountTypes == null)
        {
            throw new ArgumentNullException(nameof(discountTypes));
        }

        _discountTypes = discountTypes;
    }

    public void Register<T>() where T : IDiscountRule, new()
    {
        _discountTypes.Add(typeof(T));
    }

    /// <inheritdoc />
    public decimal CalculateDiscount(OrderItem item)
    {
        decimal totalDiscount = 0;

        foreach (var discountType in _discountTypes)
        {
            IDiscountRule rule = Activator.CreateInstance(discountType) as IDiscountRule;

            if (rule != null)
            {
                totalDiscount += rule.CalculateDiscount(item);
            }
        }

        return totalDiscount;
    }
}

Вы можете использовать составное правило со списком типов:

var item = new OrderItem
{
    ItemId = 1,
    Price = 50,
    Quantity = 2
};

// composite rule with types
var compositeRule = new CompositeDiscountRule(new List<Type>
{
    typeof(GoldDiscountRule),
    typeof(BasicDiscountRule)
});

decimal discount = compositeRule.CalculateDiscount(item); // discount = 12.0

Или, в качестве альтернативы, используя дженерики:

var item = new OrderItem
{
    ItemId = 1,
    Price = 50,
    Quantity = 2
};

// composite rule using generics
compositeRule = new CompositeDiscountRule();
compositeRule.Register<BasicDiscountRule>();
compositeRule.Register<SilverDiscountRule>();

decimal discount = compositeRule.CalculateDiscount(item); // discount = 7.0
0 голосов
/ 03 ноября 2018

Пожалуйста, прочитайте о шаблон Декоратор . Это структурный шаблон проектирования, который позволяет вам присоединять новые поведения к объектам, помещая их в объекты-оболочки, которые содержат эти поведения.

Я думаю, что это поможет вам решить первую проблему

полезная ссылка: https://refactoring.guru/design-patterns/decorator

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...