为什么用结构性模式?
结构性模式
关注点“怎样组合对象/类
?”所以我们关注下类的组合关系类结构型模式
关心类的组合,由多个类可以组合成一个更大的(继承)对象结构型模式
关心类与对象的组合,通过关联关系
在一个类中定义另一个类的实例对象(组合)- 根据“
合成复用原则
”,在系统中尽量使用关联关系来替代继承关系
,因此大部分结构型模式都是对象结构型模式
。
- 适配器模式(Adapter Pattern):两个不兼容接口之间适配的桥梁。
- 桥接模式(Bridge Pattern):相同功能抽象化与实现化解耦,抽象与实现可以独立升级。
- 过滤器模式(Filter、Criteria Pattern):使用不同的标准来过滤一组对象。
- 组合模式(Composite Pattern):相似对象进行组合,形成树形结构。
- 装饰器模式(Decorator Pattern):向一个现有的对象添加新的功能,同时又不改变其结构。
- 外观模式(Facade Pattern):向现有的系统添加一个接口,客户端访问此接口来隐藏系统的复杂性。
- 享元模式(Flyweight Pattern):尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
- 代理模式(Proxy Pattren):一个类代表另一个类的功能。
🍭结构性模式之桥接模式(Bridge Pattern)
🍎定义
- 系统设计期间, 如果这个类里面的一些东西会扩展很多,这个东西就应该分离出来。
将抽象与实现解耦,使两者都可以独立变化
- 在现实生活中,某些类具有两个或多个维度的变化,如图形既可以按形状分,又可以按颜色分。如何设计类似于 Photoshop 这样的软件,能画不同形状和颜色的图形呢?如果用继承方式,m 种形状和 n 种颜色的图形就有 m*n 种,不但对应的子类很多,而且扩展困难。不同颜色和字体的文字、不同品牌和功率的汽车。
- 桥接将继承转为关联,降低类之间的耦合度,减少代码量。
桥接(Bridge)模式包含以下主要角色:
- 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
- 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
- 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
- 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
🍔代码实现
/**
* 抽象手机类:手机有各种销售渠道价格都不一样
*/
public abstract class AbstractPhone {
// 真正引起此类变化的一个维度直接抽取出来,通过组合的方式接起来
AbstractSale sale;// 分离渠道【桥接的关注点】
// abstract int getPrice();// 如果折磨写需要多个实现。违反开闭原则
// 当前手机的描述
abstract String getPhone();
public void setSale(AbstractSale sale) {
this.sale = sale;
}
}
/**
* 抽象销售渠道
*/
public abstract class AbstractSale {
private String type;
private Integer price;
public AbstractSale(String type, Integer price) {
this.type = type;
this.price = price;
}
String getSaleInfo() {
return "渠道:" + type + " ===> 价格:" + price;
}
}
public class IPhone extends AbstractPhone{
@Override
String getPhone() {
return "IPhone" + sale.getSaleInfo();
}
}
/**
* 线下渠道
*/
public class OfflineSale extends AbstractSale{
public OfflineSale(String type, Integer price) {
super(type, price);
}
}
/**
* 线上渠道
*/
public class OnlineSale extends AbstractSale{
public OnlineSale(String type, Integer price) {
super(type, price);
}
}
/**
* 学生渠道
*/
public class StudentSale extends AbstractSale{
public StudentSale(String type, Integer price) {
super(type, price);
}
}
/**
* 省去了创建很多类
*/
public class MainTest {
public static void main(String[] args) {
IPhone iPhone = new IPhone();
iPhone.setSale(new OfflineSale("线下", 999));
System.out.println(iPhone.getPhone());
iPhone.setSale(new OnlineSale("线上", 888));
System.out.println(iPhone.getPhone());
iPhone.setSale(new OnlineSale("学生", 1));
System.out.println(iPhone.getPhone());
}
}
IPhone渠道:线下 ===> 价格:999
IPhone渠道:线上 ===> 价格:888
IPhone渠道:学生 ===> 价格:1
把真正引起此类变化的一个维度直接抽取出来,通过组合的方式接起来
🍕应用场景
- 什么场景用到?
- 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。
- 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
- 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。
- InputStreamReader桥接模式。An InputStreamReader is a bridge from
byte streams
tocharacter streams
。