1、代理模式
为什么要有代理模式?
代理模式能够增强本类的方法。可以通过三种方式来完成代理模式
①静态代理:其实就是把需要被代理的类聚合到对应的代理类。本类实现接口,然后聚合到代理类。代理类构造方法接收被代理类,并且开启一个方法增强代理方法。
问题:代理类也需要实现本类的同一个接口,如果需要很多代理的类,那么就会发生类爆炸的问题
代码
接口
public interface ITeacherDao {
void teach();
}
被代理类
public class TeacherDao implements ITeacherDao{
@Override
public void teach() {
System.out.println("教授课程");
}
}
②动态代理:其实就是在内存的时候动态创建代理类,原理就是利用反射获取被代理类的信息。好处就是不需要实现接口,可以通过一个固定的代理工厂来处理这些代理类创建。工厂类需要接受被代理类对象,反射获取属性。
代理类工厂
public class ProxyFactory {
//维护的对象
Object target;
public ProxyFactory(Object target) {
this.target=target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader()
, target.getClass().getInterfaces()
,
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态代理方法");
// 对象的方法。
method.invoke(target, args);
System.out.println("执行结束");
return null;
}
});
}
}
③Cglib:主要是处理那些没有实现接口但是仍然想增强方法的类。原理就是创建这个类的子类,重写这个代理方法。同样也是要保管一个被代理对象到代理工厂类上,而且需要实现对应接口和方法。
public class ProxyFactory implements MethodInterceptor{
Object target;
public ProxyFactory(Object target) {
this.target=target;
}
public Object getProxyInstance() {
//1.工具类
Enhancer enhancer=new Enhancer();
//2.设置父类
enhancer.setSuperclass(target.getClass());
//3.回调函数
enhancer.setCallback(this);
//4.创建子类
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("Cglib ");
Object invoke = method.invoke(target, arg2);
System.out.println("结束");
return invoke;
}
}
2.桥接模式
为什么要有桥接模式?
为了分开抽象类和行为接口类。好处就是能够方便类的拓展,抽象类和接口类就像一座桥一样,每次需要用到什么类就可以直接通过抽象这一层来寻找。主要可以解决,手机品牌,样式等组合比较多的。品牌的call方法不同,这就是行为接口类,样式就是抽象类。使用桥接模式的关键就是区分好抽象与行为。
桥接模式的四种角色
①抽象类
②抽象类的具体实现类
③行为接口
④行为接口实现类
这样的划分好处就是无论拓展抽象类这层还是接口行为类这层都可以快速拓展,而且不影响客户端。也就是他们分开了两层抽象和行为。
实例:JDBC源码下面的Connection可以通过DriverManager的判断,决定使用哪一个connection相当于就是行为接口。而Manager就是一个具体实现类(而且也充当抽象类)。如果Connection要拓展只需要实现Connection接口就可以了。
3、外观模式
为什么要有外观模式?
比如现在要处理电影开播,是不是要处理屏幕、声响、爆米花等的开关和播放?如果是客户端直接调用这些类的方法,万一某个设备发生改变,或者方法拓展,客户端都需要进行修改,违反ocp原则。那么解决的方法最好就是有一个类可以专门处理这些流程,无论子系统类如何修改最后客户端只需要调用类的固定方法就可以了。那么就可以用到外观模式,想当于就是一个界面类,里面聚合了所有的子系统类,比如屏幕、声响,并且根据需要创建方法,把这些子系统类的方法调用排好序,做好流程调用。
外观类
public class HomeTheaterFacade {
private DVDPlayer dvdPlayer;
private Popcorn popcorn;
private Projector projector;
private Screen screen;
private TheaterLight theaterLight;
private Stereo stereo;
public HomeTheaterFacade() {
dvdPlayer=DVDPlayer.getInstance();
popcorn=Popcorn.getInstance();
projector=Projector.getInstance();
screen=Screen.getInstance();
theaterLight=TheaterLight.getInstance();
stereo=Stereo.getInstance();
}
public void ready() {
popcorn.on();
popcorn.pop();
screen.down();
stereo.on();
projector.on();
dvdPlayer.on();
}
public void play() {
dvdPlayer.play();
}
public void off() {
dvdPlayer.plased();
dvdPlayer.off();
screen.up();
stereo.off();
popcorn.off();
}
}
具体的实例:Mybatis的Configuration,很多子系统类Factory组合到里面去,并且调用newMetaObject方法根据Factory返回对应的MetaObject。其中会调用到这些Factory的方法,并形成流程执行。
4、享元模式
为什么要有享元模式?
原因就是一个对象如果需要重复使用,如果我们不停创建就会造成内存的浪费。比如一个网站里面大部分对象和元素需要重复使用,那么这个使用就可以共享这些对象和元素。通过一个池。而享元模式就是通通过一个池来保存这些对象,这些对象共同点就是有内部状态,用于区分是否需要存入池中。如果没有才存储。
享元模式的内外部状态解释:
①外部状态:就是相当于是五子棋的坐标,对象的标识
②内部状态:五子棋的颜色,黑白。是不是无论有多少个五子棋都会只分为2种放入池中,那么两个对象就可以存入池中
享元模式的角色
①FlyWeight:抽象享元类,定义外部和内部状态
②ConcreteFlyWeight:具体享元类,实现对应的抽象方法
③UsharedFlyWeight:不共享的享元,不放入池中
④工厂类:也就是池子,提供获取共享对象方法
factory
public class WebSiteFactory {
private static Map<String,ConcreteWebSite> map=new HashMap<String, ConcreteWebSite>();
public static ConcreteWebSite getWebSite(String type) {
if(map.containsKey(type)) {
return map.get(type);
}else {
map.put(type, new ConcreteWebSite(type));
return map.get(type);
}
}
public static int getSize() {
return map.size();
}
}
外部状态(独立一个类,导致享元模式更复杂)
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name) {
this.name=name;
}
}
具体享元类
public class ConcreteWebSite extends WebSite{
public ConcreteWebSite(String type) {
setType(type);
}
@Override
public void use(User user) {
System.out.println("网站的类型是:"+type+" ,网站的使用者是"+user.getName());
}
}
抽象享元类
public abstract class WebSite {
String type="";
public abstract void use(User user);
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
5.装饰者模式
为什么要有装饰者模式?
现在有一个需求就是买一杯饮料和加入各种配料。正常做法就是创建各种类并且有各种组合。第二种就是饮料抽象类里面配置了配料。第一种的问题就是类爆炸,第二种就是配料修改麻烦。所以要用到装饰者模式。其实就是饮料是主体,各种配料就是辅助。每次加入一种配料,那么就用原来那杯饮料(加上配料的)聚合到新创建的配料类里面。这么说可能有点难懂,代码会好懂一些。
装饰者模式的角色
①抽象类:也就是饮料和配料的父类
②继承抽象类的饮料类
③继承抽象类的配料类,也就是Decorator
Drink(抽象类)
public abstract class Drink {
private String des;
private float price=0.0f;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public abstract float cost();
}
Coffee(其中一种品种的饮料继承抽象类,主要实现cost方法)
public class Coffee extends Drink{
@Override
public float cost() {
return super.getPrice();
}
}
Coffee继承类(设定好具体价和名称。)
public class ShortCoffee extends Coffee{
public ShortCoffee() {
super.setDes("shortcoffee");
super.setPrice(7.0f);
}
}
Decorator(聚合Drink后也就是被修饰者,就能够通过方法调用来处理他们的总共价格以及说明)
public class Decorator extends Drink{
Drink drink;
public Decorator(Drink drink) {
this.drink=drink;
}
@Override
public float cost() {
// TODO Auto-generated method stub
//当前装饰者价钱加上饮料的所有价格
return super.getPrice()+drink.cost();
}
@Override
public String getDes() {
// TODO Auto-generated method stub
return super.getDes()+" 价格是:"+super.getPrice()+" & "+drink.getDes();
}
}
Decorator具体类
public class Chocolate extends Decorator{
public Chocolate(Drink drink) {
super(drink);
super.setPrice(5.0f);
super.setDes("一杯巧克力");
}
}
public class Milk extends Decorator{
public Milk(Drink drink) {
super(drink);
super.setPrice(3.0f);
super.setDes("一杯牛奶");
}
}
6.组合模式
为什么要用到组合模式?
为了解决树形结构问题,也就是大学里面有很多学院,学院下有很多专业的管理
组合模式的角色
①叶子节点
②Component:管理子部件,对象声明接口,大家都共用这个接口
③Composite:存储子部件,实现共用方法
简单来说就是Component定义了子部件的add和remove等方法,Composite来实现这些方法,每个Composite的处理方法add或remove可能不相同。叶子节点通常不需要实现方法,比如专业。其实就是A是B的子部件,那么A就通过list的泛型聚合到B上,B是C的子部件,B也用同样方式聚合到C上。
Component
public abstract class OrganizationComponent {
private String name;
private String des;
public void add(OrganizationComponent organizationComponent) {
throw new UnsupportedOperationException();
}
public void remove(OrganizationComponent organizationComponent) {
throw new UnsupportedOperationException();
}
public abstract void print();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
/**
* @param name
* @param des
*/
public OrganizationComponent(String name, String des) {
super();
this.name = name;
this.des = des;
}
}
University(Composite)
public class University extends OrganizationComponent{
List<OrganizationComponent> list=new ArrayList<OrganizationComponent>();
public University(String name,String des) {
super(name, des);
}
@Override
public void add(OrganizationComponent organizationComponent) {
list.add(organizationComponent);
}
@Override
public void remove(OrganizationComponent organizationComponent) {
list.remove(organizationComponent);
}
@Override
public void print() {
System.out.println("--------"+this.getName()+"--------");
for(OrganizationComponent organizationComponent:list) {
organizationComponent.print();
}
}
}
College(Composite)
public class College extends OrganizationComponent{
List<OrganizationComponent> list=new ArrayList<OrganizationComponent>();
public College(String name,String des) {
super(name, des);
}
@Override
public void add(OrganizationComponent organizationComponent) {
list.add(organizationComponent);
}
@Override
public void remove(OrganizationComponent organizationComponent) {
list.remove(organizationComponent);
}
@Override
public void print() {
System.out.println("--------"+this.getName()+"--------");
for(OrganizationComponent organizationComponent:list) {
organizationComponent.print();
}
}
}
Department
public class Client {
public static void main(String[] args) {
University qingHuaUniversity=new University("清华大学","中国第一学府");
College college=new College("计算机学院", "好学员");
College college2=new College("通信学院", "通信好");
college.add(new Department("计算机与科学", "1"));
college.add(new Department("软件工程", "好"));
college2.add(new Department("通信工程", "1"));
qingHuaUniversity.add(college);
qingHuaUniversity.add(college2);
qingHuaUniversity.print();
}
}
Client
public class Client {
public static void main(String[] args) {
University qingHuaUniversity=new University("清华大学","中国第一学府");
College college=new College("计算机学院", "好学员");
College college2=new College("通信学院", "通信好");
college.add(new Department("计算机与科学", "1"));
college.add(new Department("软件工程", "好"));
college2.add(new Department("通信工程", "1"));
qingHuaUniversity.add(college);
qingHuaUniversity.add(college2);
qingHuaUniversity.print();
}
}
7.模板方法模式
为什么要有模板方法模式?
原因就是固定流程的方法,可以通过模板方法来完成对应流程调用
模板方法角色
①抽象类:定义模板方法和抽象方法
②具体实现类:主要就是实现抽象方法。
比如豆浆有很多品种,他们制作流程一直,但是add配料不同,那么抽象类豆浆就定义add抽象方法,让RedBeanSoyaMilk继承SoyaMilk并且实现抽象方法,并且调用模板方法make就能够处理固定的select,add,soak,beat流程处理。
SoyaMilk(抽象类)
public abstract class SoyaMilk {
final void make() {
select();
add();
soak();
beat();
}
public void select() {
System.out.println("选择黄豆");
}
public abstract void add();
public void soak() {
System.out.println("浸泡黄豆");
}
public void beat() {
System.out.println("打碎黄豆");
}
}