中介者模式
如果多个对象和类之间相互耦合,那么它们之间的关系就会变得杂乱无章,此时引入一个中间者,让其对类和对象之间的操作进行统一管理,减少耦合。
本例中,由于要吃火锅,妻子(或者其他家人朋友)来煮火锅,需要购买多种菜品,但是由于妻子不想出门,便让丈夫作为中间者外出到各个商店采购需要的原材料。
主要行为:
- 煮饭
- 买菜
- 卖菜
主要对象:
- 老公
- 妻子
- 商店
- 菜品
主要行为对应接口:
public interface Cook {
void cooking(Food food);
}
public interface BuyFoods {
void addGrocery(SaleFoods saleFoods);
List<Food> buy(String name);
}
public interface SaleFoods {
Food sale();
String getGroceryName();
}
主要对象:
因为菜品可能会有很多种,把菜品给抽象出来,丈夫去买菜的时候只需要记住它购买的菜而不是菜刀,到了生鲜商店之后再拿出自己的清单将详细的菜品买回去就可以了。
public abstract class Food {
public abstract String getName();
}
public class Maodu extends Food {
@Override
public String getName() {
return "毛肚";
}
}
public class Yachang extends Food {
@Override
public String getName() {
return "鸭肠";
}
}
老公买菜,可能需要购买的菜在一个生鲜超市里面并不能买到老婆给他的清单里的所有菜品,需要维护一个商店的集合。
public class Husband implements BuyFoods {
private final List<SaleFoods> saleFoodsList;
public Husband(){
saleFoodsList = new ArrayList<>();
}
@Override
public void addGrocery(SaleFoods saleFoods) {
saleFoodsList.add(saleFoods);
}
/**
* 购买菜品
* 此时假设一个商店只卖一种菜,并且是不同的,我们只需到每个商店购买一个菜即可
* 如果需要根据菜品名来购买指定的菜,则需要修改{@link SaleFoods#sale()}添加菜名,且在每个商店,如{@link GroceryA}维护一个菜品的集合
* 即可根据菜名在对应的商店买到相应的菜
* @param name 店铺名
* @return 商店买到的菜品
*/
@Override
public List<Food> buy(String name) {
List<Food> foods = new ArrayList<>();
for (SaleFoods saleFoods : saleFoodsList) {
if(saleFoods.getGroceryName().equals(name)){
foods.add(saleFoods.sale());
}
}
return foods;
}
}
商店为耦合对象,可根据需要添加或者减少:
public class GroceryA implements SaleFoods {
@Override
public Food sale() {
return new Maodu();
}
@Override
public String getGroceryName() {
return "groceryA";
}
}
public class GroceryB implements SaleFoods {
@Override
public Food sale() {
return new Yachang();
}
@Override
public String getGroceryName() {
return "groceryB";
}
}
妻子或者其他家人朋友,如果没有老公,这些类都可能直接和商店耦合
public class Wife implements Cook {
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
public void cooks(List<Food> foods){
for (Food food : foods) {
cooking(food);
}
}
@Override
public void cooking(Food food) {
LOGGER.info("wife is cooking: {}",food.getName());
}
}
//直接拷贝了一份GrandMother
public class GrandMother implements Cook {
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
public void cooks(List<Food> foods){
for (Food food : foods) {
cooking(food);
}
}
@Override
public void cooking(Food food) {
LOGGER.info("grandmother is cooking: {}",food.getName());
}
}
测试类
public class AppMain {
public static void main(String[] args) {
SaleFoods groceryA = new GroceryA();
SaleFoods groceryB = new GroceryB();
Husband husband = new Husband();
husband.addGrocery(groceryA);
husband.addGrocery(groceryB);
List<Food> foodsA = husband.buy("groceryA");
List<Food> foodsB = husband.buy("groceryB");
Wife wife = new Wife();
wife.cooks(foodsA);
GrandMother grandMother = new GrandMother();
grandMother.cooks(foodsB);
}
}
测试结果:
14:59:28.215 [main] INFO com.example.designpattern.mediator2.member.Wife - wife is cooking: 毛肚
14:59:28.223 [main] INFO com.example.designpattern.mediator2.member.GrandMother - grandmother is cooking: 鸭肠
注:本例中引入了
implementation 'ch.qos.logback:logback-classic:1.2.10'
可以看出,妻子和奶奶只关心需要煮的菜,而不关心需要去哪家商店才能购买这些菜。而丈夫则作为中间者,减少了家人们和商店之间的耦合关系,此时就算再加一个兄弟姐妹,也不会说他们还要关心去哪里购买;商店开业卖菜或者倒闭了也不需要通知丈夫的家人,因为买菜是丈夫的事情。
综上,中介者模式(mediator)是为了减少类和对象之间的耦合关系,防止关系变得像图一样复杂。
参考:https://github.com/iluwatar/java-design-patterns/blob/master/mediator/README.md