设计模式——结构型

一、 外观模式

提供统一接口,用来访问子系统中的一群接口

适用:

  • 子系统复杂
  • 构建多层系统结构,利用外观对象作为每层入口

优点:

  • 简化调用过程,无需深入子系统
  • 减少系统依赖,松散耦合
  • 更好划分访问层次
  • 符合迪米特法则(最少知道)

缺点:

  • 增加子系统,扩展子系统行为易引入风险
  • 不符合开闭原则
// 外观类
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();
    }
}

猜你喜欢

转载自www.cnblogs.com/JL916/p/12643004.html
今日推荐