聊一聊设计模式(三)
前言
憋在家里的第8天,今天开始进入结构型设计模式。
思维导图
结构型设计模式是从程序的结构上解决模块之间的耦合问题。
***模式
定义:为其他对象提供一种***以控制对这个对象的访问。
这个模式的几个角色分为以下:
- Subject:抽象主题类。
- RealSubject:真实主题类,客户端由Proxy来间接调用。
- Proxy:***类
这个模式就像你和代购的存在一样,你提出需求,由代购来帮你购买。这个句子里基本上就概括了整个***模式的全貌。客户端就是我们需求者,而真实主题就是你要找的代购帮你买,最后一个***,找谁买。
以下用代码表示静态***。
/** * 抽象主题类 * 中心主题,买东西。 */ public interface Shop { void buy(); } /** * 真实主题类 * 有这么一个人,可以干这件事,他就是*** */ public class Person implements Shop { @Override public void buy() { System.out.println("购买"); } } /** * ***类 * 你要告诉自己找那个代购买 */ public class WhoBuy implements Shop { private Shop shop; WhoBuy(Shop shop){ this.shop = shop; } @Override public void buy() { shop.buy(); } } /** * 客户端类 * 就是这个想买东西的人了 */ public class User { public static void main(String[] args) { Shop person = new Person(); Shop purchase = new WhoBuy(person); purchase.buy(); } }
静态***,主要是为了让人更好的理解***模式。在开发中主要还是使用反射机制来完成的,也就是动态***模式。
/** * 动态***类 */ public class DynamicPurchase implements InvocationHandler { private Object object; DynamicPurchase(Object object){ this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(object, args); if(method.getName().equals("buy")){ System.out.println("买上"); } return result; } } /** * 客户端类 */ public class User { public static void main(String[] args) { Shop person = new Person(); DynamicPurchase dynamicPurchase = new DynamicPurchase(person); ClassLoader loader = person.getClass().getClassLoader(); Shop purchase = (Shop) Proxy.newProxyInstance(loader, new Class[]{Shop.class}, dynamicPurchase); purchase.buy(); } }
和静态***的不同就在于***类,使用反射机制。
这种***模式的优点:
- 真实主题类只关注本身的业务逻辑。
- 真实主题类和***类实现了公共接口,不必担心主题类的修改影响***类。
装饰模式
动态地给一个对象添加一些额外的职责。
这个模式的角色有:
- Component:抽象组件。
- ConcreteComponent:组件具体实现类。
- Decorator:抽象装饰者,用于增加Component类的功能。
- ConcreteDecorator:装饰者的具体实现
人是一个慢慢学习的生物,从一开始只会咿咿呀呀,经过学习,学会了数学,英语。这个时候数学、英语,两个科目就是一种装饰了。
/** * 抽象组件 * 作为一个人,必然会有学习的能力。 */ public abstract class Person { public abstract void learn(); } /** * 组件具体实现类 * 人一开始只会咿咿呀呀 */ public class Me extends Person { @Override public void learn() { System.out.println("咿咿呀呀"); } } /** * 抽象装饰类 * 有一个老师教书育人 */ public abstract class Teacher extends Person { private Person person; Teacher(Person person){ this.person = person; } @Override public void learn() { person.learn(); } } /** * 装饰具体类 * 这个老师教数学,也就教会了孩子 */ public class MathTeacher extends Teacher { MathTeacher(Person person) { super(person); } public void teach(){ System.out.println("学会了数学"); } @Override public void learn() { super.learn(); teach(); } } // 具体使用 public class Main { public static void main(String[] args) { Person person = new Me(); MathTeacher mathTeacher = new MathTeacher(person); mathTeacher.learn(); } }
优点:
- 能够动态的为对象增加功能。
- 装饰类和组件类互不干扰。
缺点: - 不论是装饰类,还是组件类都继承自
Component
,如果Component
发生了改变,子类必然收到巨大的冲击。 - 装饰层数不宜过多,不仅影响效率,排查也比较苦难。
外观模式
要求一个子系统 的外部与内部的通信必须通过一个统一的对象进行。
这个模式的角色有:
- Facade:外观类
- Subsystem:子系统类
这里觉得之前看到的武侠的例子非常好。
一个武侠本身分为招式、内功、经脉三个系统,每次放招都是根据三个子系统的合理使用来释放。
/** * 三大子系统 */ public class 经脉 { public void jingmai(){ System.out.println("开启经脉"); } } public class 内功 { public void JiuYang(){ System.out.println("使用九阳神功"); } public void QianKun(){ System.out.println("使用乾坤大挪移"); } } public class 招式 { public void QiShangQuan(){ System.out.println("使用七伤拳"); } public void ShengHuoLing(){ System.out.println("使用圣火令"); } } /** * 外观类 * 也就是张无忌 */ public class 张无忌 { private JingMai jingMai; private NeiGong neiGong; private ZhaoShi zhaoShi; 张无忌(){ jingMai = new JingMai(); neiGong = new NeiGong(); zhaoShi = new ZhaoShi(); } public void QianKun(){ jingMai.jingmai(); neiGong.QianKun(); } public void QiShang(){ jingMai.jingmai(); neiGong.JiuYang(); zhaoShi.QiShangQuan(); } }
给外人看到的只有张无忌的出招是七伤拳,但是不知道内部的具体操作,这也就是外观类的整体展现方式了。
优点:
- 所有的依赖都是出现在外观类的,子系统间互不干扰。
- 具体实现对用户隐藏,也就是用户和子系统处于松耦合状态,同时保障了子系统的安全性。
缺点:业务一旦出现变更,就需要直接修改外观类。
享元模式
使用共享对象有效地支持大量细粒度的对象。
该模式下的对象有
- Flyweight:抽象享元角色。
- ConcreteFlyweight:具体享元角色
- FlyweightFactory:享元工厂,负责对象创建和管理。
其实往简单了说就是一种缓冲池的技术。
/** * 享元工厂 */ public class VipFactory { private static Map<String, Vip> cache = new HashMap<>(); public static Vip getVip(String number){ if(cache.containsKey(number)){ return cache.get(number); }else{ Vip vip = new Vip(number); cache.put(number, vip); return vip; } } } /** * 享元角色 */ public class Vip implements IVip { private String name; private String number; Vip(String number){ this.number = number; } @Override public void showVip(String number) { if (number.equals(number)) { System.out.println(name == null? "空": name); } } } /** * 享元抽象角色 */ public interface IVip { void showVip(String number); }
在享元工厂中我们显而易见的看到了由static
修饰的cache
变量,这就是一个缓冲,如果缓冲中存在,就从缓冲中取,不存在则创建。