По какому шаблону можно создать объект одного класса, но заполнить его свойства по-разному?

у меня такой класс

public class OwnerWithholding
    {

        private decimal ManagementFeePct;

        private decimal TotalManagementFee;

        private decimal OperationalFeesPct;

        private decimal TotalOperationalFees;

}

И у меня есть метод расчета, который создает объект этого класса, заполняет его некоторыми арифметическими операциями и возвращает этот объект.

public OwnerWithholding CalculationMethod1(Reservation r, SqlConnection conn)
        {
            OwnerWithholding result = new OwnerWithholding();

           // result.ManagementFeePct  = some data from Fees table in DB + value 
           //from another db - constant value..

           // Also with other properties - with some operations on data

           //result.TotalManagementFee = ..
           // result.OperationalFeesPct = ..
           // result. TotalOperationalFees = ..

            return result;
        }

И теперь он работает нормально. Но этот метод расчета является лишь одним из вариантов заполнения данных.

Есть еще один метод расчета, реализованный совершенно по-другому, но заполняющий точно такие же свойства объекта. И у меня их может быть больше.

Мне нужен паттерн, который позволил бы мне создавать объекты одного класса, просто указав метод расчета, который нужен. Мне нравится шаблон стратегии, где алгоритмами будут методы, заполняющие объекты, которые их вызвали. Но выглядит не очень. Может быть, фабричный метод здесь был бы уместнее, но я не знаю, как его реализовать.


person AtlasPromotion    schedule 10.10.2019    source источник
comment
Вы ищете шаблон компоновщика?   -  person Corak    schedule 10.10.2019
comment
Если вам нужен шаблон Factory, возможно, абстрагируйте общие свойства в AbstractFactory, а затем заставьте конкретные Factory реализовать определенные типы этого объекта. Поэтому каждый раз, когда у вас появляется новый тип, вам понадобится конкретный реализатор Factory. Но Фабрика имеет больше смысла, когда создание объекта происходит из нескольких мест в вашем коде.   -  person Rakesh    schedule 10.10.2019
comment
@Rakesh, да, у меня есть создание этого объекта в нескольких местах моего кода, и в каждом месте нужен объект с определенными данными в нем в соответствии с выбранным вариантом   -  person AtlasPromotion    schedule 10.10.2019
comment
Кроме того, вы говорите, что только одно из значений свойств задается динамически, поэтому Builder также является хорошим шаблоном, как только что предложил @Corak.   -  person Rakesh    schedule 10.10.2019
comment
@Corak, не подумайте - билдер предназначен для нескольких шагов создания, которые могут быть разными, но у меня есть только один   -  person AtlasPromotion    schedule 10.10.2019
comment
@Rakesh, извините, может быть, я неправильно написал - в этом методе задаются все свойства объекта.   -  person AtlasPromotion    schedule 10.10.2019
comment
@AtlasPromotion - но этот шаг отличается для разных целей, верно? Никто не мешает вам иметь конструктор всего за один шаг. - т. е. у вас могут быть BuilderWithCalculationMethodA и BuilderWithCalculationMethodB и т. д. -- если вы можете выделить методы расчета, вы приблизитесь к паттерну стратегии. Почему это выглядит не очень хорошо?   -  person Corak    schedule 10.10.2019
comment
Спасибо за идею с конструктором, буду думать. Это выглядит не очень хорошо, потому что в этом случае я должен сделать что-то вроде этого: calculationMethod.SetCalculationStrategy(new CalculationMethod1()); return calculationMethod.CreateAndFillObject; Не так ли?   -  person AtlasPromotion    schedule 10.10.2019
comment
@AtlasPromotion - эти разные типы предопределены, т. Е. У вас может быть только 5 из этих типов, а не любое возможное количество. Если комбинации бесконечны, конструктор - это способ сделать это, нет смысла иметь Фабрику - просто дайте вам знать.   -  person Rakesh    schedule 10.10.2019
comment
@Rakesh, типы - методы расчета?   -  person AtlasPromotion    schedule 10.10.2019
comment
@AtlasPromotion - Да, методы расчета   -  person Rakesh    schedule 10.10.2019
comment
@Rakesh, извини, не понял насчёт бесконечных комбинаций - сейчас у меня всего 2 метода, но в будущем их может быть больше   -  person AtlasPromotion    schedule 10.10.2019
comment
@Corak, извините, забыл упомянуть вас в комментарии :)   -  person AtlasPromotion    schedule 10.10.2019


Ответы (1)


Редактировать: Судя по комментариям OP, похоже, что только ОДИН метод в классе должен быть установлен несколькими способами. Шаблон Template (или Builder) лучше подходит в этом случае, а не Factory.

Шаблон шаблона.

а. Абстрактный базовый класс, который устанавливает свойства по умолчанию, но не включает одно свойство (Получить ингредиенты), которое будет заполнено конкретными классами.

    public abstract class PizzaCreator
    {
        public abstract string GetIngredients { get; }
        public string Bake { get; set; } = "Bake at 400F for 30 minutes";
        public string Deliver { get; set; } = "Deliver in custom box";
    }

б. Два класса Pizza, на данный момент просто переопределяющие абстрактное свойство

    public class CheesePizza : PizzaCreator
    {
        public override string GetIngredients
        {
            get { return GetMyIngredients(); }
        }

        string GetMyIngredients()
        {
            return "Lots of Cheese!";
        }
    }

    public class PepperoniPizza : PizzaCreator
    {
        public override string GetIngredients
        {
            get { return GetMyIngredients(); }
        }

        string GetMyIngredients()
        {
            return "Lots of Meats!";
        }
    }

Здесь я создаю экземпляры Pizza

            var pepPizza = new PepperoniPizza();
            var chessePizza = new CheesePizza();

Вы даже можете направить эти творения через класс/метод Factory.

Исходный ответ: вот шаблон абстрактной фабрики.

Этот код входит в библиотеку классов Factory.

интерфейс a.ICar

    public interface ICar
    {
        string Name { get; set; }
        int Doors { get; set; }
        string EngineCapacity { get; set; }
    }

b.Абстрактный автомобильный завод

    public abstract class AbstractCarFactory
    {
        public abstract ICar CreateCar(CarType type);
    }

c. Две бетонные машины -

    internal class NissanPickUpTruck : ICar
    {
        public string Name { get; set; } 
        public int Doors { get; set ; }
        public string EngineCapacity { get ; set ; }
    }

    internal class NissanSportsCar: ICar
    {
        public string Name { get; set; } 
        public int Doors { get; set; }
        public string EngineCapacity { get; set; }
    }

г. Бетонный завод

    public class NissanFactory : AbstractCarFactory
    {
        public override ICar CreateCar(CarType type)
        {
            switch (type)
            {
                case CarType.PickupTruck:
                    return new NissanPickUpTruck{Name = "Titan", Doors = 6, EngineCapacity = "V12"};
                case CarType.SportsCar:
                    return new NissanSportsCar{Name = "350Z", Doors = 2, EngineCapacity = "V6"};
                default:
                    throw new Exception();
            }
        }
    }

Наконец, звонки из внешнего проекта

            var nissanFactory = new NissanFactory();
            var sportsCar = nissanFactory.CreateCar(CarType.SportsCar);
            var pickUpTruck = nissanFactory.CreateCar(CarType.PickupTruck);

Но, как и в другом комментарии, Builder тоже стоит проверить.

person Rakesh    schedule 10.10.2019
comment
И если у меня есть методы расчета, должен ли я помещать эти разные методы в разные классы, такие как NissanPickup и NissanSport? И вернуть объект в этот метод, а потом просто вызвать case CarType.PickupTruck: return NissanPickupCalcMethod(); Или будет лучше, если у меня в этих классах будут конструкторы вместо метода? - person AtlasPromotion; 10.10.2019
comment
Да разные классы бетона с соответствующими расчетами - person Rakesh; 10.10.2019
comment
Подождите, вы возвращаете конкретные классы, а не только методы расчета, слово «методы» сбивает с толку, я не знаю, имеете ли вы в виду методы в смысле C# или методы в смысле бизнес-правил. - person Rakesh; 10.10.2019
comment
В смысле С#. Если я возвращаю конкретные классы, я не могу передать все значения их свойств в new NissanPickUpTruck{Name = Titan, Doors = 6, EngineCapacity = V12}; потому что у меня есть огромные методы, в которых эти значения вычисляются и присваиваются свойствам объекта - person AtlasPromotion; 10.10.2019
comment
Если вы хотите обновить только ОДНО свойство в классе несколькими способами, вам нужны шаблоны Builder и Template. В Фабрике вы создаете конкретные классы, а не просто назначаете одно свойство. - person Rakesh; 10.10.2019
comment
Хм, шаблон шаблона? В котором у нас есть скелет алгоритма, а затем добавлены определенные шаги в подклассах? Но как я могу использовать это в моем случае? - person AtlasPromotion; 10.10.2019
comment
Проверьте эту ссылку - tutorialspoint.com/design_pattern/template_pattern.htm. В ней объясняется, как использовать Шаблон шаблона. - person Rakesh; 10.10.2019
comment
Обновлено для включения шаблона шаблона. - person Rakesh; 10.10.2019
comment
@Rakesh Хороший ответ, но он принес бы гораздо больше пользы, если бы вы придерживались примера, приведенного в OP, который не содержит пиццы или автомобили IMO. - person CKing; 10.10.2019
comment
:) Я не понял его правил ведения бизнеса, я уже один раз ошибся. Я чувствовал, что «Машины и пиццы» легко понять и понять, но я согласен, что его объекты в примерах были бы лучше. - person Rakesh; 10.10.2019
comment
@AtlasPromotion. Удалось ли вам использовать шаблон шаблона для решения вашей проблемы? - person Rakesh; 12.10.2019