Дизайн декоратора и фабричный дизайн

Функция subprocess.run() существует только в Python 3.5 и более поздней.

Однако достаточно легко выполнить обратную передачу:

def run(*popenargs, input=None, check=False, **kwargs):
    if input is not None:
        if 'stdin' in kwargs:
            raise ValueError('stdin and input arguments may not both be used.')
        kwargs['stdin'] = subprocess.PIPE

    process = subprocess.Popen(*popenargs, **kwargs):
    try:
        stdout, stderr = process.communicate(input)
    except:
        process.kill()
        process.wait()
        raise
    retcode = process.poll()
    if check and retcode:
        raise subprocess.CalledProcessError(
            retcode, process.args, output=stdout, stderr=stderr)
    return retcode, stdout, stderr

нет поддержки тайм-аутов и нет настраиваемого класса для завершенной информации о процессе, поэтому я возвращаю только данные retcode, stdout и stderr. В противном случае он делает то же самое, что и оригинал.

1
задан George 28 March 2019 в 04:05
поделиться

5 ответов

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

Лучшим примером пиццы было бы взять урок пиццы, который может выполнять следующие действия:

  • подают пиццу
  • подают безалкогольные напитки

и затем пытается добавить функциональность, которая может служить салаты. Таким образом, упрощенная версия этого класса пиццы может выглядеть следующим образом:

public class Pizzeria {
    public String orderPizza() {
        System.out.println("you ordered a pizza");
    }

    public String orderSoftDrink() {
        System.out.println("you ordered a soft drink");
    }
}

Чтобы реализовать здесь шаблон декоратора, мы оборачиваем существующий класс Pizzeria, а затем добавляем некоторую новую функцию public String orderPizza () { System.out.println («Вы заказали пиццу»); } public String orderSoftDrink () {System.out.println («Вы заказали безалкогольный напиток»); } ality:

public class NewPizzeria {
    private Pizzeria pizzeria;

    public NewPizzeria() {
        pizzeria = new Pizzeria();
    }

    public String orderPizza() {
        pizzeria.orderPizza();
    }

    public String orderSoftDrink() {
        pizzeria.orderSoftDrink();
    }

    public String orderSalad() {
        System.out.println("you ordered a salad");
    }
}

Ключевым моментом здесь является то, что класс NewPizzeria «владеет» своим собственным объектом Pizzeria. По большей части, он просто отражает ту же функциональность, которая уже есть у Pizzeria. Но он также добавляет некоторые новые функции.

Шаблон проектирования декоратора полезен в тех случаях, когда класс уже существует, который в основном соответствует вашим потребностям, но вам нужно что-то еще и , вы также не можете переписать этот класс (например, потому что он является частью некоторой библиотеки) , В этом случае перенос этого класса и использование шаблона декоратора - один из хороших вариантов.

0
ответ дан Tim Biegeleisen 28 March 2019 в 04:05
поделиться

Концептуально в шаблоне декоратора выходные данные одной обработки идут как входные данные для другой обработки.

Итак, в вашем случае это должно быть так:

getToppingFoo(getToppingBar(...(getXBaseSizePizzaCost())

, который разрешается в:

FooToppingCost + (BarToppingCost + ... ( Cost of pizza with base of X size )

Далее, вы можете определить фабричный класс для получения Pizza объекта различных размеров, скажем, Standard, Medium, Large. Логика одинакова независимо от того, какой язык вы выбираете.

0
ответ дан Saurav Sahu 28 March 2019 в 04:05
поделиться

Давайте посмотрим ниже, чтобы начать с

  1. Шаблон декоратора в чистом виде намеревается enhance existing behavior of an object at run time without destroying the existing interface of the object.
  2. Декорирование подразумевает улучшение существующего поведения объекта.
  3. Декорированный объект имеет тот же (базовый) интерфейс, что и декорируемый базовый объект.

Вопрос: Объект извлекается из его класса, который является временем компиляции. Теперь, как бы вы продолжили улучшать поведение?

Ответ: Используя шаблон Decorator, также известный как обертка.

Пример: у вас есть файл, который можно зашифровать, скажем, методов шифрования в настоящее время 5, в результате будет зашифрованный файл. Зашифрованный файл может быть снова зашифрован. Кроме того, давайте предположим, что существует 5 способов заархивировать файл, который впоследствии может увеличиться. Файл может быть зашифрован с помощью methodEA, затем может быть заархивирован с помощью MethodZA, затем снова может быть зашифрован с помощью methodEB, аналогичные последовательности могут создавать разные файлы результатов.

Один из хороших способов, как показано ниже.

public class TextFile{
       public void create(){/*somecode*/};
       public void format(){//code for default plain text};
}

public class AEncryptedFile extends TextFile{
        private TextFile wrapped;
        public AEncryptedFile(TextFile file){
              this.wrapped = file;
        }
        public void format(){
               super.format();
               //add enhacements for encryption type A
        }
}

public class BEncryptedFile extends TextFile{
        private TextFile wrapped;
        public BEncryptedFile(TextFile file){
              this.wrapped = file;
        }
        public void format(){
               super.format();
               //add enhacements for encryption type B
        }
}

public class AZippedFile extends TextFile{
        private TextFile wrapped;
        public BEncryptedFile(TextFile file){
              this.wrapped = file;
        }
        public void format(){
               super.format();
               //add enhacements for zip type A
        }
}

public class BZippedFile extends TextFile{
        private TextFile wrapped;
        public BEncryptedFile(TextFile file){
              this.wrapped = file;
        }
        public void format(){
               super.format();
               //add enhacements for zip type B
        }
}

public void UserClass{
    public static void main(String[] args){
          TextFile file = new BZippedFile(new AEncryptedFile(new TextFile()));
          file.format();
}

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

Объект TextFile был декорирован (обтеканием) объектом AEncryptedFile, который дополнительно декорируется BZippedFile, в каждом из этих дополнительных украшений дополнительное улучшение был создан для существующего объекта

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

Примечание : Реализация шаблона декоратора имеет структуру LinkedList.

0
ответ дан nits.kk 28 March 2019 в 04:05
поделиться
0
ответ дан Ray Tayek 28 March 2019 в 04:05
поделиться

Декоратор - это класс, который расширяет функциональность другого класса. Декоратор обычно реализует тот же интерфейс, так что декорированный объект можно использовать вместо базового. Хорошим примером является компрессор и / или шифратор, применяемый к файлу или, в более общем смысле, к реализации потока данных, как показано в ответе @ nits.kk . [1116 ]

В случае пиццы мы должны определить, какое поведение нам нужно:

public interface Pizza {
    public String getIngredients();  // comma separated
    public double getTotalPrice();
}

Пицца состоит из двух основных типов ингредиентов: обязательная единая основа и необязательные множественные начинки. Каждый ингредиент имеет свою цену.

public class PizzaIngredient {
    private double getPrice() {
        return 0.0;
    }
}

База пиццы сама по себе является самой простой пиццей, поэтому она должна реализовывать интерфейс Pizza. У него есть размер как его атрибут (и цена, конечно). Мы могли бы реализовать размер как отдельный класс, но я не считаю его разумным - он недостаточно универсален, чтобы быть полезным вне вселенной пиццы, и недостаточно сложен, чтобы заслужить свой собственный интерфейс.

public class PizzaBase extends PizzaIngredient implements Pizza {
    public PizzaBase(String size) {
        this.size = size;
    }

    public String getIngredients() {
        return size + " base";  // the only ingredient is this base
    }
    public double getTotalPrice() {
        return getPrice();      // the base-only pizza costs the base cost
    }
    private double getPrice() {
        if(size == "small")
            return 2.0;
        if(size == "medium")
            return 2.5;

        return 3.0;            // large and undefined
    }

    private final String size;
}

Теперь нам нужны начинки. Они будут добавлены поверх пиццы в качестве декораторов: пицца плюс топпинг - это тоже пицца, поэтому самый верхний топинг будет представлять всю композицию. Список ингредиентов такой пиццы - это список ингредиентов основной пиццы, а также наименование ее самой верхней части. Аналогично общая цена.

public class PizzaTopping extends PizzaIngredient implements Pizza {
    public PizzaTopping(String name, Pizza pizza) {
        this.name = name;
        this.pizza = pizza;
    }

    public String getIngredients() {
        return pizza.getIngredients() + ", " + getName();
    }
    public double getTotalPrice() {
        return pizza.getTotalPrice() + getPrice();
    }
    public String getName() {
        return name;
    }

    private final String name;
    private final Pizza pizza;
}

Давайте определим некоторые конкретные начинки:

public class MozarellaTopping extends PizzaTopping {
    public MozarellaTopping(Pizza pizza) {
        super("mozarella", pizza);
    }

    private double getPrice() {
        return 0.5;
    }
}

public class MushroomTopping extends PizzaTopping {
    public MushroomTopping(Pizza pizza) {
        super("mushroom", pizza);
    }

    private double getPrice() {
        return 2.0;
    }
}

public class PepperoniTopping extends PizzaTopping {
    public PepperoniTopping(Pizza pizza) {
        super("pepperoni", pizza);
    }

    private double getPrice() {
        return 1.5;
    }
}

public class GreenOliveTopping extends PizzaTopping {
    public GreenOliveTopping(Pizza pizza) {
        super("green olive", pizza);
    }

    private double getPrice() {
        return 1.2;
    }
}

Хорошо, это много классов; но какой из них и когда нам понадобится?

Здесь фабрика присоединяется к команде. Фабрика - это класс для создания объектов некоторых классов. Он используется, чтобы скрыть детали создания за кулисами, особенно когда созданные объекты являются сложными или имеют разные конкретные классы. Когда результирующие объекты создаются как автономные объекты, фабричный класс может быть просто пространством имен со статическим методом в нем. OTOH, если объекты создаются в каком-то контексте, фабрика может быть объектом, связанным с контекстом (например, параметризованным) и использующим этот контекст в процессе создания.

Мы можем использовать фабрику для создания ингредиентов для пиццы по желанию, в соответствии с пользовательской информацией. Большинство ингредиентов - это начинки, которые нужно наносить поверх уже существующей пиццы, поэтому давайте передадим пиццу на фабрику, чтобы в результате получить украшенную пиццу. Особый случай - создание базы для пиццы, которая не наносится на другую пиццу; в этом случае параметр pizza игнорируется, поэтому мы можем передать null.

public class PizzaFactory {
    public static Pizza getPizza(Pizza pizza, String name)
    {
        if ( name.equals("small") || name.equals("medium") || name.equals("large") )
            return new PizzaBase(name);
        else if ( name.equals("mozarella") )
            return new MozarellaTopping(pizza);   // add topping to the pizza
        else if ( name.equals("mushroom") )
            return new MushroomTopping(pizza);
        else if ( name.equals("pepperoni") )
            return new PepperoniTopping(pizza);
        else if ( name.equals("green olive") )
            return new GreenOliveTopping(pizza);

        return null;
    }
}

Теперь мы готовы построить нашу пиццу.

class PizzaTest {
    public static void main(String[] args) {
        DecimalFormat priceFormat = new DecimalFormat("#.##");

        Pizza pizza;

        pizza = PizzaFactory.getPizza(null, "small");
        System.out.println("The small pizza is: " + pizza.getIngredients());
        System.out.println("It costs " + priceFormat.format(pizza.getTotalCost()));

        pizza = PizzaFactory.getPizza(null, "medium");
        pizza = PizzaFactory.getPizza(pizza, "mozarella");
        pizza = PizzaFactory.getPizza(pizza, "green olive");

        System.out.println("The medium pizza is: " + pizza.getIngredients());
        System.out.println("It costs " + priceFormat.format(pizza.getTotalCost()));

        String largePizzaOrder[] = { "large", "mozarella", "pepperoni",
                                     "mushroom", "mozarella", "green olive" };

        pizza = null;
        for (String cmd : largePizzaOrder)
            pizza = PizzaFactory.getPizza(pizza, cmd);

        System.out.println("The large pizza is: " + pizza.getIngredients());
        System.out.println("It costs " + priceFormat.format(pizza.getTotalCost()));
    }
}

Предупреждение: в приведенном выше коде есть некоторые подводные камни и ярлыки.

Наиболее важным является отсутствие проверки ввода: при поступлении неожиданной команды, фабрика вернет null, что вызовет сбой при будущем использовании getIngredients() или getTotalCost().

Другой - жесткое кодирование цен в конкретные классы. Фактическое решение должно было бы использовать некоторый прайс-лист и получать цены либо при создании ингредиента (и хранить выбранные цены в объектах ингредиента), либо при использовании, т. Е. В методе getCost() (который потребовал бы некоторого доступа к прайс-листу от ингредиенты пиццы).

0
ответ дан CiaPan 28 March 2019 в 04:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: