Java 装饰设计与工厂设计模式
我试图找出如何使用用户输入,并根据用户输入输出某些信息。有人能举一个简单的例子来说明如何在一家简单的比萨饼店中使用装饰图案吗Java 装饰设计与工厂设计模式,java,design-patterns,Java,Design Patterns,我试图找出如何使用用户输入,并根据用户输入输出某些信息。有人能举一个简单的例子来说明如何在一家简单的比萨饼店中使用装饰图案吗 所以我知道如何处理装饰器模式,只是用户输入部分让我卡住了。假设用户想要做一个比萨饼,他们会首先选择比萨饼的大小,然后根据自己的需要添加很多配料。然后,当他们完成后,他们将看到他们添加的内容以及添加的内容(如Receipt)的总价。这是用Java编写的 就概念而言,在decorator模式中,一个处理的输出作为另一个处理的输入 所以在你的情况下,应该是这样的: getTop
所以我知道如何处理装饰器模式,只是用户输入部分让我卡住了。假设用户想要做一个比萨饼,他们会首先选择比萨饼的大小,然后根据自己的需要添加很多配料。然后,当他们完成后,他们将看到他们添加的内容以及添加的内容(如Receipt)的总价。这是用Java编写的 就概念而言,在decorator模式中,一个处理的输出作为另一个处理的输入 所以在你的情况下,应该是这样的:
getToppingFoo(getToppingBar(...(getXBaseSizePizzaCost())
public class Pizzeria {
public String orderPizza() {
System.out.println("you ordered a pizza");
}
public String orderSoftDrink() {
System.out.println("you ordered a soft drink");
}
}
决议如下:
FooToppingCost + (BarToppingCost + ... ( Cost of pizza with base of X size )
此外,您可以定义一个factory类来获取各种大小的对象,例如标准、中型和大型对象。无论您选择何种语言,逻辑都是相同的。您对装饰器模式用途的期望/理解可能有点偏离。decorator模式旨在包装一组现有的功能,以提供一些新的功能,以及已有的功能 一个更好的比萨饼例子是参加一个比萨饼班,它可以做以下事情:
- 供应比萨饼
- 供应软饮料
getToppingFoo(getToppingBar(...(getXBaseSizePizzaCost())
public class Pizzeria {
public String orderPizza() {
System.out.println("you ordered a pizza");
}
public String orderSoftDrink() {
System.out.println("you ordered a soft drink");
}
}
为了在这里实现decorator模式,我们包装现有的Pizzeria
类,然后添加一些新函数publicstringorderpisa(){
System.out.println(“你点了比萨饼”);
}
公共字符串orderSoftDrink(){
System.out.println(“您点了一杯软饮料”);
}
性:
这里的关键点是NewPizzeria
类“拥有”自己的Pizzeria
对象。在大多数情况下,它只是提供了与比萨店相同的功能。但是,它也添加了一些自己的新功能
如果一个类已经存在,并且基本上满足了您的需求,但是您需要其他东西,并且您也无法重写该类(例如,因为它是某个库的一部分),那么decorator设计模式非常有用。在这种情况下,包装该类并使用decorator模式是一个很好的选择。让我们从以下几点开始
在运行时增强对象的现有行为,而不破坏对象的现有接口李>
装饰意味着增强对象的现有行为
装饰对象与被装饰的基本对象具有相同的(基本)接口李>
问题:对象是从其编译时类派生的。现在,你将如何继续加强这种行为
答:通过使用装饰器模式(也称为包装器)
示例:您有一个可以加密的文件,假设加密方法当前为5,结果将是加密文件。加密文件可以再次加密。另外,我们假设有5种压缩文件的方法,这些方法以后也会增加。一个文件可以用methoda加密,然后用MethodZA压缩,然后再用methodb加密,相似的序列可以生成不同的结果文件
下面是一个好方法
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();
}
在上面的示例代码中,可以这样说
文本文件的一个对象已被AEncryptedFile对象修饰(通过包装),而BZippedFile进一步修饰了该对象,在这些修饰中,每个修饰都对现有对象进行了额外的增强
通过这种方式,可以在运行时将TextFile的现有对象传递给各种方法,并且可以通过将该对象包装到TextFile子类型的另一个对象中来修饰该对象
注意:Decorator模式实现具有LinkedList的结构。Decorator是扩展另一个类功能的类。装饰器通常实现相同的接口,以便可以使用装饰对象而不是基本对象。一个很好的例子是在文件上应用的压缩程序和/或加密程序,或者更一般地,在数据流实现上应用的压缩程序和/或加密程序,如@所示
对于比萨饼,我们应该定义我们需要的行为:
public interface Pizza {
public String getIngredients(); // comma separated
public double getTotalPrice();
}
比萨饼由两种主要成分组成:一种是强制性的单底比萨,另一种是选择性的多顶比萨。每种配料都有自己的价格
public class PizzaIngredient {
private double getPrice() {
return 0.0;
}
}
pizza base本身就是一个最简单的pizza,因此它必须实现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 MozzarellaTopping extends PizzaTopping {
public MozzarellaTopping(Pizza pizza) {
super("mozzarella", 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;
}
}
好的,那是很多课程;但我们什么时候需要它们呢
在这里,一家工厂加入了团队。工厂是用于创建某些类的对象的类。它用于隐藏场景背后的创建细节,尤其是当创建的对象很复杂或属于不同的具体类时。当结果对象作为独立实体创建时,factory类可以只是一个名称空间,其中包含一个静态方法。OTOH,如果对象是在某个上下文中创建的,则工厂可以是与上下文关联的对象(例如,参数化的对象),并在创建时使用该上下文
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, "mozzarella");
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", "mozzarella", "pepperoni",
"mushroom", "mozzarella", "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()));
}
}