gof分类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
这里只总结几种比较重要的:
———————————————————————————————————————
一、创建型:
1.简单工厂模式
简单工厂模式通常就是这样,一个工厂类 XxxFactory,里面有一个静态方法,根据我们不同的参数,使用swtich +case 返回不同的派生自同一个父类(同一职责)(或实现同一接口)的实例对象。
把或者各个类型的都统一放到./工厂产品/目录下,工厂传入要匹配的类型, 以匹配类型为文件名。需要实例化的时候就require该文件,这样也保证了各个开发人员的代码不冲突。后期也易扩展,新增一种类型的用户,只需新增一个类型的文件即可符合开闭原则。
2.工厂模式(需要使用两个或两个以上的工厂时)
3.抽象工厂模式(通过抽象产品来抽象了工厂)
涉及定义某个产品的一系列附件的集合时, 不再定义组件工厂,直接定义产品工厂,由产品工厂来定义所需组件
4.单例模式
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
懒汉式单例(在第一次调用的时候实例化自己):
public class Singleton {
//不再提供给其他的地方实例化
private Singleton() {}
private static Singleton single=null;
//静态工厂方法,Singleton的唯一实例只能通过getInstance()方法访问。为空的时候才生产
//如果把实例写在成员变量里则法不能把其他不需要实例的常用方法放入这里,会导致在不需要时创建实例。
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式(只记录两种):
1、在getInstance方法上加同步synchronized
2、静态内部类(既实现了线程安全,又避免了同步带来的性能影响)
Java机制规定,内部类只有在调用内部类方法第一次调用的时候才会被加载(实现了延迟加载效果),而且其加载过程是线程安全的(实现线程安全)。内部类加载的时候实例化一次instance。
另外,外部类加载的时候,内部类不会被加载,静态内部类只是调用的时候用了外部类的名字而已。
public class Singleton {
private static class LazyHolder { //静态类懒汉式视为延迟加载的饿汉式
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
饿汉式单例(饿汉式单例类.在类初始化时,已经自行实例化,天生是线程安全的):
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}
5.建造者模式 参考
是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
(例如造汽车与买汽车)
一般包括以下几个角色:
- builder(抽象建造者):给出一个抽象结论,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的对象部件的创建。
- ConcreteBuilder(具体建造者):实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。在构造过程完成后,提供产品的实例。
- Director(指导者):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
- Product(产品类):要创建的复杂对象。
适用场景
需要生产的产品对象有复杂的内部结构。
需要生产的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。
在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
———————————————————————————————————————
二、结构型
1.适配器模式
适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配,简单点理解就是平常所见的转接头,转换器之类的存在。
适配器模式有两种:类适配器、对象适配器、接口适配器
前二者在实现上有些许区别,作用一样,第三个接口适配器差别较大。
类适配器模式:
当我们要访问的接口A中没有我们想要的方法 ,却在另一个接口B中发现了合适的方法,我们又不能改变访问接口A,在这种情况下,我们可以定义一个适配器p来进行中转,这个适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法(虽然它目前不是我们的菜),然后再继承接口B的实现类BB,这样就完成了一个简单的类适配器。
1 public class Adapter extends Usber implements Ps2 {
2 //在实现自己接口A的同时继承要额外访问的接口B的实现;类Usber
3 @Override
4 public void isPs2() {
5 isUsb();
6 }
7
8 }
对象适配器模式 :
我们可以定义一个适配器p来进行中转,这个适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法(虽然它目前不是我们的菜),然后在适配器P中定义私有变量C(对象)(B接口指向变量名),再定义一个带参数的构造器用来为对象C赋值,再在A接口的方法实现中使用对象C调用其来源于B接口的方法。
1 public class Adapter implements Ps2 {
2 //
3 private Usb usb;
4 public Adapter(Usb usb){
5 this.usb = usb;
6 }
7 @Override
8 public void isPs2() {
9 usb.isUsb();
10 }
11
12 }
接口适配器模式 :
当存在这样一个接口,其中定义了N多的方法,而我们现在却只想使用其中的一个到几个方法,如果我们直接实现接口,那么我们要对所有的方法进行实现,哪怕我们仅仅是对不需要的方法进行置空(只写一对大括号,不做具体方法实现)也会导致这个类变得臃肿,调用也不方便,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。
使用场景:
(1)类:想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
(2)对象:我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
(2)接口:想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。
2.代理模式
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用
在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
包含以下角色:
ISubject:抽象接口。该接口是 真实对象 和它的 代理 共用的接口。
RealSubject:真实主题角色,是实现抽象主题接口的类。
Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
静态代理
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
//以买房的中介过程为例
//Proxy:代理角色
package main.java.proxy.impl;
import main.java.proxy.BuyHouse;//中介服务接口
public class BuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public BuyHouseProxy(final BuyHouse buyHouse) { //主体(服务)角色买房实现(需求)传入
this.buyHouse = buyHouse;
}
@Override
public void buyHosue() { //中介自己的买房实现
System.out.println("买房前准备");
buyHouse.buyHosue();
System.out.println("买房后装修");
}
}
———————————————————————————————————————
三、行为型
1.观察者模式
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象(观察者)会收到通知并自动更新
其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。
结构图:
上图有以下角色:
抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
声明了添加、删除、通知观察者方法
public interface Observerable {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
public interface Observer {
public void update(String message);
}
具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。
//注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
private List list;
private String message;
public WechatServer() { //使用微信公众号订阅的例子
list = new ArrayList();
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if(!list.isEmpty())
list.remove(o);
}
//遍历
@Override
public void notifyObserver() { //对所有用户进行状态更改, 这里是消息数+1
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
}
public void setInfomation(String s) {
this.message = s;
System.out.println("微信服务更新消息: " + s);
//消息更新,通知所有观察者
notifyObserver();
}
具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
实现更新方法供被观察者调用
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送消息: " + message);
}