前言
很久没有写关于设计模式的博客了,实在是没有太多的精力去写。但个人觉得设计模式在我们的日常开发中还是挺重要的,它提高了软件的可维护性。因此还是有必要坚持学习设计模式,写博客主要是为了加深我对设计模式的理解。今天我要讲的设计模式是装饰者模式(Dectorator),它是结构型模式的一员。如果有什么讲的不正确的地方,希望各位大佬指正。
思考题
首先,让我们思考下面的问题:
有这么一家奶茶店,希望开发一个计算奶茶价格的软件,当客户点一杯奶茶,并且加入某几样配料时,需要及时的计算出这杯奶茶的价格,下面是奶茶和配料的价格。 原味奶茶:10 珍珠:2 椰果:3 巧克力:5 例子:如果用户点椰果奶茶,那么他的价格就是 原味奶茶+椰果=13。
当没有学习过装饰者模式时,我会给出下面的解决思路:
Ingredient.java:
public interface Ingredient { Integer price(); }
配料接口:所有的配料都要实现这个接口,该接口有一个价格方法。
Chocolate.java:
public class Chocolate implements Ingredient { public Integer price() { return 5; } }
Coconut.java:
public class Coconut implements Ingredient { public Integer price() { return 3; } }
Pearl.java:
public class Pearl implements Ingredient { public Integer price() { return 2; } }
以上的上我的配料的实现类,他们都实现了 Ingredient 接口,并且实现了 price 方法。
MilkTea.java:
import java.util.List; import java.util.ArrayList; public class MilkTea { private ListingredientList = new ArrayList<>(); public void addIngredient(Ingredient ingredient) { ingredientList.add(ingredient); } public Integer countPrice() { Integer allPrice = 10; for (Ingredient ingredient : ingredientList) { allPrice += ingredient.price(); } return allPrice; } }
以上是奶茶类的实现,里面有一个 ingredientList 成员变量,使用 addIngredient 就可以增加配料,调用 countPrice 计算奶茶的价格。
TestMain.java:
public class TestMain { public static void main(String... args) { MilkTea milkTea = new MilkTea(); milkTea.addIngredient(new Chocolate()); System.out.println("巧克力奶茶:" + milkTea.countPrice()); MilkTea milkTea_1 = new MilkTea(); milkTea_1.addIngredient(new Coconut()); milkTea_1.addIngredient(new Pearl()); System.out.println("珍珠椰果奶茶:" + milkTea_1.countPrice()); } }
下面给出该实现的uml类图。
装饰者设计模式
定义:动态的给特定对象赋予新的功能.
类图:
从上面的类图我们可以总结出以下几点:
1.实现装饰者模式,我们需要有一个公共接口,我们的装饰者和被装饰者都需要继承这个接口.
2.为了更好地维护代码,上面将被装饰者的公共的代码提取到了父类中,子类通过继承这个父类可以很容易的实现不同的特性.
3.在父类的接口中实现了 Material 接口,以保证装饰者可以被其他装饰者装饰.
4.父类中有成员变量 Material ,以保证每个装饰者都知道自己装饰的是什么对象.
重构思考题
Material.java:
public interface Material { Integer price(); }
MilkTea.java:
public class MilkTea implements Material { @Override public Integer price() { return 10; } }
Ingredient.java:
public abstract class Ingredient implements Material { private Material material; public Ingredient(Material material) { this.material = material; } @Override public Integer price() { return material.price() + getPrice(); } public abstract Integer getPrice(); }
Chocolate.java:
public class Chocolate extends Ingredient { public Chocolate(Material material) { super(material); } @Override public Integer getPrice() { return 5; } }
Coconut.java:
public class Coconut extends Ingredient { public Coconut(Material material) { super(material); } @Override public Integer getPrice() { return 3; } }
Pearl.java:
public class Pearl extends Ingredient { public Pearl(Material material) { super(material); } @Override public Integer getPrice() { return 2; } }
MainTest.java:
public class MainTest { public static void main(String... args) { Material milkTea = new Chocolate(new MilkTea()); System.out.println("巧克力奶茶:" + milkTea.price()); Material milkTea_1 = new Coconut(new Pearl(new MilkTea())); System.out.println("珍珠椰果奶茶:" + milkTea_1.price()); } }