目录
1、单例模式
2、策略模式
工厂模式
3、工厂方法模式
4、抽象工厂模式
5、门面模式
6、调停者模式
7、装饰者模式
8、责任链模式
参考文献
就是在项目中只需要一个实例存在,下面列出了几个单例模式的写法
/**
* 单例模式 饿汉式
*/
public class Singleton01 {
//首先定义一个静态的实例
private final static Singleton01 INSTANCE = new Singleton01();
//然后把构造方法私有化
private Singleton01() {
}
public static Singleton01 getInstance() {
return INSTANCE;
}
}
/**
* 单例模式 懒汉式
* 这个多线程中同时调用的时候会有问题
* 解决办法就是 使用 synchronized 加锁
* 但是这样虽然解决了多线程的问题,效率会大大降低
* 优化了一下,就是锁住代码块,
* 注意:方法中有两个判断,是有必要的,这个是为了
*/
public class Singleton04 {
//首先定义一个静态的实例
private static volatile Singleton04 INSTANCE;
//然后把构造方法私有化
private Singleton04() {
}
//使用的时候才加载
public static synchronized Singleton04 getInstance() {
//注意:这里的两个判断是有必要的,第一个判断是为了
//如果不为空,就不用加锁,加快了效率
if (INSTANCE == null) {
synchronized (Singleton04.class) {
if (INSTANCE == null) {
//为了测试,休眠1毫秒
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton04();
}
}
}
return INSTANCE;
}
}
/**
* 静态内部类的方式
* 这个是完美的写法之一
* 线程安全是由jvm来保证的,
* 虚拟机加载class的时候只加载一次,所以Sl06Holder也只加载一次
* 所以INSTANCE也只加载一次,所以也不用加锁
*/
public class Singleton06 {
//首先把构造方法私有化
private Singleton06() {
}
//然后定义一个静态内部类
private static class Sl06Holder {
//初始化了Singleton06
private final static Singleton06 INSTANCE = new Singleton06();
}
public static Singleton06 getInstance() {
return Sl06Holder.INSTANCE;
}
}
/**
* 使用枚举类 不仅可以解决线程同步
* 还可以防止反序列化
* 枚举单例
* 这种也是完美的写法之一
*/
public enum Singleton07 {
INSTANCE;
//业务方法
public void test(){
}
}
策略模式封装的就是做一件事情的不同的执行方式,用的最多的就是Collections.sort()
方法,里面实现Comparator
接口来进行排序,下面咱们模仿Comparator 来演示策略模式。
比如,现在有一个学生的实体类,需要根据年龄、身高、体重、分数等条件分别进行排序,这个时候,使用策略模式来实现的话,就比较好
Comparator
public interface Comparator<T> {
int compare(T o1, T o2);
}
public class Sorter {
//使用选择排序的方法,把数据进行排序
public static <T> void sort(List<T> list, Comparator<? super T> c) {
for (int i = 0; i < list.size(); i++) {
int min = i;
for (int j = i + 1; j < list.size(); j++) {
min = c.compare(list.get(j), list.get(min)) == -1 ? j : min;
}
swap(list, i, min);
}
}
private static <T> void swap(List<T> list, int i, int min) {
T temp = list.get(i);
list.set(i, list.get(min));
list.set(min, temp);
}
public static <T> void insort(T[] ts, Comparator<? super T> c) {
for (int i = 0; i < ts.length; i++) {
int min = i;
for (int j = i + 1; j < ts.length; j++) {
min = c.compare(ts[j], ts[min]) == -1 ? j : min;
}
swap(ts, i, min);
}
}
private static <T> void swap(T[] ts, int i, int min) {
T temp = ts[i];
ts[i] = ts[min];
ts[min] = temp;
}
}
Comparator
接口,比如身高,其他的原理一样,在这里我就不写了。public class HeightComparator implements Comparator<Student> {
//根据判断学生的身高来进行排序
//从小到大
@Override
public int compare(Student o1, Student o2) {
if (o1.getHeight() > o2.getHeight()) return 1;
else if (o1.getHeight() < o2.getHeight()) return -1;
return 0;
}
}
public class Test2 {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student("张三", 34, 70.5, 178, 87));
list.add(new Student("李四", 45, 88.5, 187, 65));
list.add(new Student("王五", 23, 98.5, 180, 89));
//根据年龄排序
Sorter.sort(list, (o1, o2) -> {
if (o1.getAge() > o2.getAge()) return 1;
else if (o1.getAge() < o2.getAge()) return -1;
else return 0;
});
System.out.println("年龄:" + list.toString());
//根据体重排序
Sorter.sort(list,new WeightComparator());
System.out.println("体重:" + list.toString());
//根据身高排序
Sorter.sort(list, new HeightComparator());
System.out.println("身高:" + list.toString());
//根据分数排序
//也可以通过Java1.8中的Lambda表达式来完成
Sorter.sort(list, (o1, o2) -> {
if (o1.getScore() > o2.getScore()) return 1;
else if (o1.getScore() < o2.getScore()) return -1;
else return 0;
});
System.out.println("分数:" + list.toString());
}
}
定义:
任何可以产生对象的方法或类,都可以称之为工厂,单例也是一种工厂,数据静态工厂
//产品接口,产品都需要实现这个接口
public interface Moveable {
void go();
}
//汽车 实现 Moveable接口
public class Car implements Moveable {
@Override
public void go() {
System.out.println("car go...");
}
}
//飞机 实现 Moveable接口
public class Plane implements Moveable {
@Override
public void go() {
System.out.println("plane flying...");
}
}
工厂代码如下:
/**
* 汽车工厂
*/
public class CarFactory {
public static Car create() {
System.out.println("a car created");
return new Car();
}
}
/**
* 飞机工厂
*/
public class PlaneFactory {
public static Plane create() {
System.out.println("a Plane created");
return new Plane();
}
}
测试类:
public class Test {
public static void main(String[] args) {
Moveable m1 = CarFactory.create();
m1.go();
Moveable m2 = PlaneFactory.create();
m2.go();
}
}
运行结果如下:
抽象工厂是对工厂方法模式进行抽象
例子需要的类如下:
产品的抽象类如下
/**
* 食物抽象方法
*/
public abstract class Food {
public abstract void Fname();
}
/**
* 交通工具的抽象类
*/
public abstract class Vehicle {
public abstract void go();
}
/**
* 武器的抽象类
*/
public abstract class Weapon {
public abstract void shoot();
}
工厂的抽象类如下:
/**
* 抽象工厂
*/
public abstract class abstracFactory {
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
产品的实现类如下:
//AK47 继承 Weapon
public class AK47 extends Weapon {
@Override
public void shoot() {
System.out.println("用的武器是 AK47");
}
}
//汽车 继承 Vehicle
public class Car extends Vehicle {
@Override
public void go() {
System.out.println("交通工具是 汽车");
}
}
//面包 继承 Food
public class Bread extends Food {
@Override
public void Fname() {
System.out.println("食物是 面包");
}
}
工厂的实现类如下:
public class ModernFactory extends abstracFactory {
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
@Override
public Food createFood() {
return new Bread();
}
}
测试类如下:
public class Test {
public static void main(String[] args) {
abstracFactory af = new ModernFactory();
Food food = af.createFood();
food.Fname();
Vehicle vehicle = af.createVehicle();
vehicle.go();
Weapon weapon = af.createWeapon();
weapon.shoot();
}
}
门面模式(Facade),是指提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口。使得子系统更容易使用。
通俗的讲就是在外部调用内部模块之间声明一个门面Facade
用来管理,就是外部只访问这个门面类,这个门面类去访问内部的各个模块。如下图所示:
调停者模式(Mediator)是软件设计模式的一种,用于模块间解耦,通过避免对象互相显式的指向对方从而降低耦合。
通俗的讲就是由于代码中各个模块之间需要调用,然后声明一个调停者,然后内部的代码模块之间不直接访问,模块都直接访问调停者,然后调停者向指定模块获取数据,然后把数据再返回指定模块,如下图所示:
一般门面和调停者模式配合使用,就是定义一个模块。对于外部而言就是门面者,对于内部模块而言就是调停者,如下图:
定义: 装饰者模式又被称作包装模式,就是在不改变原类文件和不使用继承的情况下,动态的给已知对象添加一些额外的功能,添加的功能还可以手动撤销。
组成部分:
1. 抽象组件(Component
): 给出一个抽象接口,以规范准备接收附件功能的对象。
2. 被装饰者(ConcreteComponent
): 抽象组件的具体实现类。
3. 装饰者组件(Decoretor
): 自己实现了抽象组件,并且持有实现了抽象组件的实例的引用,该类的职责就是为了装饰具体组件对象,定义为具体装饰者的基类。
4. 具体装饰(ConcreteDecoretor
) 是装饰者组件的具体实现类,是负责给被装饰者添加附加功能的。
结构图如下:
举例:
我们以火锅为例子。我们都知道,我们去吃火锅,我们先选锅底,有麻辣的,香辣的,番茄的等等。选完锅底以后,我们再选菜,菜有牛肉,羊肉,土豆片,鱼丸等。根据以上思路,我们可以画出一下结构图。
项目类的目录如下:
示例代码:
/**
* 抽象组件
* 火锅
*/
public interface HotPot {
//锅底和菜品
String desc();
//价格
double price();
}
/**
* 被装饰者
* 香辣火锅
*/
public class SpicyHotpot implements HotPot {
@Override
public String desc() {
return "香辣火锅(¥15)";
}
@Override
public double price() {
return 15;
}
}
/**
* 被装饰者
* 菌汤火锅
*/
public class MushroomHotpot implements HotPot {
@Override
public String desc() {
return "菌汤火锅(¥18)";
}
@Override
public double price() {
return 18;
}
}
/**
* 装饰器
* 1、抽象类(这个根据实际情况而定)
* 1、实现抽象组件的接口
* 2、拿到实现抽象组件的引用
*/
public abstract class HotPotDecorator implements HotPot {
private HotPot hotPot;
public HotPotDecorator(HotPot hotPot) {
this.hotPot = hotPot;
}
@Override
public String desc() {
return hotPot.desc();
}
@Override
public double price() {
return hotPot.price();
}
}
/**
* 具体装饰类 继承 装饰者组件
*/
public class Beef extends HotPotDecorator {
public Beef(HotPot hotPot) {
super(hotPot);
}
@Override
public String desc() {
return super.desc()+"+牛肉(¥23)";
}
@Override
public double price() {
return super.price()+23;
}
}
/**
* 具体装饰类 继承 装饰者组件
*/
public class Mutton extends HotPotDecorator {
public Mutton(HotPot hotPot) {
super(hotPot);
}
@Override
public String desc() {
return super.desc()+"+羊肉(¥16)";
}
@Override
public double price() {
return super.price()+16;
}
}
/**
* 具体装饰类 继承 装饰者组件
*/
public class Potato extends HotPotDecorator {
public Potato(HotPot hotPot) {
super(hotPot);
}
@Override
public String desc() {
return super.desc()+"+土豆片(¥8)";
}
@Override
public double price() {
return super.price()+8;
}
}
public class Main {
public static void main(String[] args) {
HotPot hp = new SpicyHotpot();
System.out.println(hp.desc() + " ,价格是:" + hp.price());
hp = new Beef(hp);
System.out.println(hp.desc() + " ,价格是:" + hp.price());
hp = new Mutton(hp);
System.out.println(hp.desc() + " ,价格是:" + hp.price());
hp = new Potato(hp);
System.out.println(hp.desc() + " ,价格是:" + hp.price());
System.out.println();
System.out.println("=================分割线=======================");
System.out.println();
HotPot hp1 = new MushroomHotpot();
System.out.println(hp1.desc() + " ,价格是:" + hp1.price());
hp1 = new Beef(hp1);
System.out.println(hp1.desc() + " ,价格是:" + hp1.price());
hp1 = new Potato(hp1);
System.out.println(hp1.desc() + " ,价格是:" + hp1.price());
}
}
运行结果如下:
定义:
责任链:是为例避免请求发送者与多个请求处理这耦合在一起,将所有请求的处理者通过千亿对象记住下一对象的引用而连城一条链,当有请求发生时,可将请求沿着这条链传递,知道有对象处理它为止。
优点:
缺点:
组成部分:
结构图:
原图地址:http://c.biancheng.net/uploads/allimg/181116/3-1Q116135Z11C.gif
例子1:请假条审批流程
在公司,规定员工请假2天以内的,组长可以批准,5天以内的需要经理批准,10天以内的需要老板批准,然后10天以上的呢,需要辞职。这个就可以使用责任链来实现
代码如下:
//领导抽象类
public abstract class Leader {
//下一个处理类的引用
private Leader next;
//处理方法
abstract void handRequest(int days);
public Leader getNext() {
return next;
}
public void setNext(Leader next) {
this.next = next;
}
}
/**
* 具体处理者
* 组长,可以批两天以内的假
*/
public class GroupLeader extends Leader {
@Override
void handRequest(int days) {
if (days <= 2) {
System.out.println("组长批准了你的 " + days + " 天假。");
} else {
if (getNext() != null) {
System.out.println("组长无权批准你的假,已提交给总经理审批");
getNext().handRequest(days);
} else {
System.out.println("没有人处理你的申请");
}
}
}
}
/**
* 具体处理者
* 经理,可以批5天以内的假
*/
public class Manager extends Leader {
@Override
void handRequest(int days) {
if (days <= 5) {
System.out.println("总经理批准了你的 " + days + " 天假。");
} else {
if (getNext() != null) {
System.out.println("总经理无权批准你的假,已提交给老板审批");
getNext().handRequest(days);
} else {
System.out.println("没有人处理你的申请");
}
}
}
}
/**
* 具体处理者
* 老板,可以批10天以内的假
*/
public class Boss extends Leader {
@Override
void handRequest(int days) {
if (days <= 10) {
System.out.println("老板批准了你的 " + days + " 天假。");
} else {
System.out.println("请假天数太多,不予批准!可以考虑辞职");
}
}
}
public class Client {
public static void main(String[] args) {
//组长
Leader groupleader = new GroupLeader();
//经理
Leader manager = new Manager();
//老板
Leader boss = new Boss();
//组长的上级是经理
groupleader.setNext(manager);
//经理的上级是老板
manager.setNext(boss);
int day = 9;
System.out.println("你请假的天数:"+day+ " 天。");
groupleader.handRequest(day);
}
}
例子2:使用Filter模拟处理Request Response
我们使用Filter来过滤前端页面传给服务器的数据,把带有Html标签的、敏感词汇的、URL地址的和笑脸的给修改了。并且还要实现 先执行完 request的过滤,然后在执行response的过滤 执行顺序如下图所示:
代码如下:
public class Request {
private String reqStr;
public String getReqStr() {
return reqStr;
}
public void setReqStr(String reqStr) {
this.reqStr = reqStr;
}
}
public class Response {
private String resStr;
public String getResStr() {
return resStr;
}
public void setResStr(String resStr) {
this.resStr = resStr;
}
}
public interface Filter {
public void doFilter(Request request, Response response, FilterChain fc);
}
public class FilterChain implements Filter {
private List<Filter> list = new ArrayList<>();
//用来记录目前该执行的链条的位置
int index = 0;
public FilterChain add(Filter filter) {
list.add(filter);
return this;
}
@Override
public void doFilter(Request request, Response response, FilterChain fc) {
if (index == list.size()) return;
Filter filter = list.get(index);
//拿到filter以后,index加1,指向下一个filer
index++;
filter.doFilter(request, response, fc);
}
}
public class HtmlFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain fc) {
String reqStr = request.getReqStr();
request.setReqStr(reqStr + "---HTML");
//当该处理类执行完request的filter以后,在外部调用链条的doFilter的方法
//执行下一个处理类的request的filter
fc.doFilter(request, response, fc);
response.setResStr(response.getResStr() + "---HTML");
}
}
public class SensitiveFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain fc) {
String reqStr = request.getReqStr();
request.setReqStr(reqStr + "---Sensi");
fc.doFilter(request, response, fc);
response.setResStr(response.getResStr() + "---Sensi");
}
}
//其他的与之类似,我就不写了
[1] 马士兵老师的视频
[2] Java设计模式:23种设计模式全面解析
[3] 责任链模式-模拟处理Reques Response