一、 外观模式
提供统一接口,用来访问子系统中的一群接口
适用:
- 子系统复杂
- 构建多层系统结构,利用外观对象作为每层入口
优点:
- 简化调用过程,无需深入子系统
- 减少系统依赖,松散耦合
- 更好划分访问层次
- 符合迪米特法则(最少知道)
缺点:
- 增加子系统,扩展子系统行为易引入风险
- 不符合开闭原则
// 外观类
public class GiftExchangeService {
// 子系统
private QualifyService qualifyService = new QualifyService();
private PointsPaymentService pointsPaymentService = new PointsPaymentService();
private ShippingService shippingService = new ShippingService();
// 开放给客户端的接口
public void giftExchange(PointsGift pointsGift) {
// 内部逻辑
if (qualifyService.isAvailable(pointsGift)) {
// 资格校验通过
if (pointsPaymentService.pay(pointsGift)) {
// 如果支付积分成功
String shippingOrderNo = shippingService.shipGift(pointsGift);
System.out.println("物流系统下单成功,订单号是:" + shippingOrderNo);
}
}
}
}
// 客户端
public class Test {
public static void main(String[] args) {
PointsGift pointsGift = new PointsGift("T恤");
GiftExchangeService giftExchangeService = new GiftExchangeService();
giftExchangeService.giftExchange(pointsGift);
}
}
二、 装饰者模式
在不改变原有对象的基础之上,将功能附加到对象上,扩展原有对象功能
适用:
- 扩展一个类的功能或给一个类添加附加职责
- 动态的给一个对象添加功能,这些功能可以再动态撤销
优点:
- 继承的有力补充,比继承灵活,不改变原有对象的情况下给对象扩展功能
- 通过使用不同装饰类及排列组合,实现不同效果
- 符合开闭原则
缺点:
- 会出现更多的代码,更多的类,增加程序复杂性
- 动态装饰,多层装饰更加复杂
// 抽象实体
public abstract class ABattercake {
protected abstract String getDesc();
protected abstract int cost();
}
// 确定实体
public class Battercake extends ABattercake {
@Override
protected String getDesc() {
return "煎饼";
}
@Override
protected int cost() {
return 8;
}
}
// 抽象装饰者
public abstract class AbstractDecorator extends ABattercake {
private ABattercake aBattercake;
public AbstractDecorator(ABattercake aBattercake) {
this.aBattercake = aBattercake;
}
@Override
protected String getDesc() {
return this.aBattercake.getDesc();
}
@Override
protected int cost() {
return this.aBattercake.cost();
}
}
// 确定装饰者1
public class EggDecorator extends AbstractDecorator {
public EggDecorator(ABattercake aBattercake) {
super(aBattercake);
}
@Override
protected String getDesc() {
return super.getDesc() + " 加一个鸡蛋";
}
@Override
protected int cost() {
return super.cost() + 1;
}
}
// 确定装饰者2
public class SausageDecorator extends AbstractDecorator {
// ...
}
// 客户端
public class Test {
public static void main(String[] args) {
ABattercake aBattercake;
aBattercake = new Battercake();
aBattercake = new EggDecorator(aBattercake);
aBattercake = new EggDecorator(aBattercake);
aBattercake = new SausageDecorator(aBattercake);
System.out.println(aBattercake.getDesc() + " 销售价格:" + aBattercake.cost());
}
}
三、 适配器模式
将一个类的接口转换成期望的另一个接口,使得原本接口不兼容的类可以一起工作
适用:
- 已经存在的类,方法与需求不匹配,但方法结果相似
- 随着软件维护,解决不同厂家生产接口不同功能类似的产品问题
优点:
- 提高类的透明性和复用,现有的类复用不需要改变
- 目标类和适配器解耦,提高程序扩展性
- 符合开闭原则
缺点:
- 编写需要全面考虑,可能会增加复杂度
- 增加系统可读难度
// Adaptee 经由 Adapter 转换为 Target
// Adaptee
public class Adaptee {
public void adapteeRequest() {
System.out.println("被适配者的方法");
}
}
// Target
public interface Target {
void request();
}
// Adpter 类适配器:继承
public class Adapter extends Adaptee implements Target{
@Override
public void request() {
//...
super.adapteeRequest();
//...
}
}
// Adapter 对象适配器:组合
public class Adapter implements Target{
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
//...
adaptee.adapteeRequest();
//...
}
}
四、 享元模式
提供类减少对象数量从而改善应用所需的对象结构模式
运用共享技术有效支持大量细粒度的对象
适用:
- 系统底层的开发,解决性能问题
- 系统有大量相似对象,需要缓冲池的场景
优点:
- 减少对象的创建,降低内存中对象数量
- 减少内存之外其他资源占用
缺点:
- 关注内/外状态,关注线程安全问题
- 程序逻辑复杂
内部状态:不随外界变化
外部状态:随外界变化
public abstract class Flyweight {
// 内部状态
public String intrinsic;
// 外部状态
protected final String extrinsic;
// 要求享元角色必须接受外部状态
public Flyweight(String extrinsic) {
this.extrinsic = extrinsic;
}
// 定义业务操作
public abstract void operate(int extrinsic);
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
public class ConcreteFlyweight extends Flyweight {
//接受外部状态
public ConcreteFlyweight(String extrinsic) {
super(extrinsic);
}
//根据外部状态进行逻辑处理
@Override
public void operate(int extrinsic) {
System.out.println("具体Flyweight:" + extrinsic);
}
}
// 享元工厂
public class FlyweightFactory {
//定义一个池容器
private static HashMap<String, Flyweight> pool = new HashMap<>();
public static Flyweight getFlyweight(String extrinsic) {
Flyweight flyweight = null;
if(pool.containsKey(extrinsic)) {
flyweight = pool.get(extrinsic);
System.out.print("已有 " + extrinsic + " 直接从池中取---->");
} else {
flyweight = new ConcreteFlyweight(extrinsic);
pool.put(extrinsic, flyweight);
System.out.print("创建 " + extrinsic + " 并从池中取出---->");
}
return flyweight;
}
}
五、 组合模式
将对象组合成树形结构以表示部分——整体层次结构,使得客户端对单个对象和组合对象保持一致的方式处理
适用:
- 希望客户端忽略组合对象与单个对象的差异
- 处理树形结构
优点:
- 清除定义分层次的复杂对象,表示对象的全部或部分层次
- 让客户端忽略层次的差异,方便对整个层次结构进行控制
- 简化客户端代码
- 符合开闭原则
缺点:
- 限制类型时会较为复杂
- 使设计变得更加抽象
// 抽象组件
public abstract class CatalogComponent {
public void add(CatalogComponent catalogComponent) {
throw new UnsupportedOperationException("不支持添加操作");
}
public void remove(CatalogComponent catalogComponent) {
throw new UnsupportedOperationException("不支持删除操作");
}
public String getName(CatalogComponent catalogComponent) {
throw new UnsupportedOperationException("不支持获取名称操作");
}
public double getPrice(CatalogComponent catalogComponent) {
throw new UnsupportedOperationException("不支持获取价格操作");
}
public void print() {
throw new UnsupportedOperationException("不支持打印操作");
}
}
// 课程
public class Course extends CatalogComponent {
private String name;
private double price;
public Course(String name, double price) {
this.name = name;
this.price = price;
}
// 覆盖 getName getPrice print
}
// 课程目录 包含课程列表
public class CourseCatalog extends CatalogComponent {
private List<CatalogComponent> items = new ArrayList<CatalogComponent>();
private String name;
private Integer level;
public CourseCatalog(String name, Integer level) {
this.name = name;
this.level = level;
}
@Override
public void add(CatalogComponent catalogComponent) {
items.add(catalogComponent);
}
@Override
public String getName(CatalogComponent catalogComponent) {
return this.name;
}
@Override
public void remove(CatalogComponent catalogComponent) {
items.remove(catalogComponent);
}
@Override
public void print() {
System.out.println(this.name);
for (CatalogComponent catalogComponent : items) {
if (this.level != null) {
for (int i = 0; i < this.level; i++) {
System.out.print(" ");
}
}
catalogComponent.print();
}
}
}
public class Test {
public static void main(String[] args) {
CatalogComponent linuxCourse = new Course("Linux课程", 11);
CatalogComponent windowsCourse = new Course("Windows课程", 11);
CatalogComponent baseCourseCatalog = new CourseCatalog("基础课程目录", 2);
CatalogComponent course1 = new Course("数据结构", 55);
CatalogComponent course2 = new Course("高等数学", 66);
baseCourseCatalog.add(course1);
baseCourseCatalog.add(course2);
CatalogComponent mainCourseCatalog = new CourseCatalog("主目录", 1);
mainCourseCatalog.add(linuxCourse);
mainCourseCatalog.add(windowsCourse);
mainCourseCatalog.add(baseCourseCatalog);
mainCourseCatalog.print();
}
}
六、 桥接模式
将抽象部分与具体实现部分分离,使他们可以独立变化
通过组合建立类之间的联系
适用:
- 抽象和具体实现之间增加灵活性
- 一个类存在多个独立变化的维度,且维度需要独立维护
- 不希望使用继承,或因为多层继承导致系统类的个数剧增
优点:
- 分离抽象部分及其具体实现部分
- 提高系统可扩展性
- 符合开闭原则
- 符合合成/复用原则
缺点:
- 增加系统的理解与设计难度
- 需要正确识别系统中两个独立变化的维度
// 实现
public interface Account {
Account openAccount();
void showAccountType();
}
// 抽象
public abstract class Bank {
protected Account account; // 桥梁
public Bank(Account account) {
this.account = account;
}
abstract Account openAccount(); // 委托给实现
}
// 抽象和实现的具体类
public class DepositAccount implements Account {
// ...
}
public class SavingAccount implements Account {
// ...
}
public class ABCBank extends Bank {
public ABCBank(Account account) {
super(account);
}
@Override
Account openAccount() {
System.out.println("打开中国农业银行账号");
account.openAccount();
return account;
}
}
public class ICBCBank extends Bank {
public ICBCBank(Account account) {
super(account);
}
@Override
Account openAccount() {
System.out.println("打开中国工商银行账号");
account.openAccount();
return account;
}
}
七、 代理模式
为其他对象提供一种代理,以控制对这个对象的访问,起到中介的作用
适用:
- 保护目标对象
- 增强目标对象
优点:
- 将代理对象与真实被调用的目标对象分离
- 一定程度上降低系统耦合度,扩展性好
- 保护目标对象
- 增强目标对象
缺点:
-
类的数目增加
-
请求处理速度变慢
-
增加系统的复杂度
-
静态代理:显式定义代理类,对同名方法进行包装
public interface BuyHouse {
void buyHouse();
}
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHouse() {
System.out.println("我要买房");
}
}
public class BuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public BuyHouseProxy(final BuyHouse buyHouse) {
this.buyHouse = buyHouse;
}
@Override
public void buyHouse() {
beforeBuyHouse();
buyHouse.buyHouse();
afterBuyHouse();
}
private void beforeBuyHouse() {
System.out.println("买房前准备");
}
private void afterBuyHouse() {
System.out.println("买房后装修");
}
}
- 动态代理:编写动态处理器,并利用反射,仅支持 interface 代理
public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("买房前准备");
Object result = method.invoke(object, args);
System.out.println("买房后装修");
return result;
}
}
public class Test {
public static void main(String[] args) {
BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(
BuyHouse.class.getClassLoader(), // ClassLoader loader:指定当前目标对象使用的类加载器
BuyHouseImpl.class.getInterfaces(), // Class<?>[] interfaces:指定目标对象实现的接口的类型
new DynamicProxyHandler(new BuyHouseImpl())); // InvocationHandler:指定动态处理器
proxyBuyHouse.buyHouse();
}
}
- CGLib代理:通过继承进行代理
public class CglibProxy implements MethodInterceptor {
private Object target;
public Object getInstance(final Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("买房前准备");
Object result = methodProxy.invoke(object, args);
System.out.println("买房后装修");
return result;
}
}
public class Test {
public static void main(String[] args){
CglibProxy cglibProxy = new CglibProxy();
BuyHouseImpl buyHouseCglibProxy = (BuyHouseImpl) cglibProxy.getInstance(new BuyHouseImpl());
buyHouseCglibProxy.buyHosue();
}
}