一、创建型
(一)简单工厂模式
(二)工厂方法模式
(三)抽象工厂模式
// 产品
public class Computer {
private Board board;
private Cpu cpu;
public Computer(Board board,Cpu cpu){
this.board = board;
this.cpu = cpu;
}
public void run(){
board.run();
cpu.run();
}
}
// 两个产品等级结构 Board和Cpu
public interface Board {
void run();
}
public interface Cpu {
void run();
}
// 产品族1
public class Board1 implements Board{
@Override
public void run() {
System.out.println("board1 run");
}
}
public class Cpu1 implements Cpu{
@Override
public void run() {
System.out.println("cpu1 run");
}
}
// 产品族2
public class Board2 implements Board{
@Override
public void run() {
System.out.println("board2 run");
}
}
public class Cpu2 implements Cpu{
@Override
public void run() {
System.out.println("cpu2 run");
}
}
// 顶级工厂,定义方法
public interface ComputerFactory {
Board makeBoard();
Cpu makeCpu();
}
// 两个子类工厂,负责创建
public class Computer1Factory implements ComputerFactory{
@Override
public Board makeBoard() {
return new Board1();
}
@Override
public Cpu makeCpu() {
return new Cpu1();
}
}
public class Computer2Factory implements ComputerFactory{
@Override
public Board makeBoard() {
return new Board2();
}
@Override
public Cpu makeCpu() {
return new Cpu2();
}
}
// 测试
public static void main(String[] args) {
ComputerFactory f1 = new Computer1Factory();
Board b1 = f1.makeBoard();
Cpu c1 = f1.makeCpu();
Computer computer1 = new Computer(b1, c1);
computer1.run();
ComputerFactory f2 = new Computer2Factory();
Board b2 = f2.makeBoard();
Cpu c2 = f2.makeCpu();
Computer computer2 = new Computer(b2, c2);
computer2.run();
}
- 增加产品族很方便,只需要添加新的产品和工厂即可。符合“开闭原则”。
// 产品族3
public class Board3 implements Board{
@Override
public void run() {
System.out.println("board3 run");
}
}
public class Cpu3 implements Cpu{
@Override
public void run() {
System.out.println("cpu3 run");
}
}
// 增加新的工厂
public class Computer3Factory implements ComputerFactory{
@Override
public Board makeBoard() {
return new Board3();
}
@Override
public Cpu makeCpu() {
return new Cpu3();
}
}
- 增加新的产品机构等级困难,需要修改顶级工厂及所有子类工厂。不符合“开闭原则”。
// 增加产品结构等级Power ,则需要在工厂中添加新的方法,所有子类工厂都必须修改。
public interface ComputerFactory {
Board makeBoard();
Cpu makeCpu();
Power makePower(); //
}
(四)建造者模式
(五)单例模式
- 饿汉模式
public class Singleton {
private Singleton(){};
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
- 饱汉模式
// 使用双重检查
public class Singleton {
private Singleton() { }
private static volatile Singleton instance = null;
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
// 使用嵌套类
public class Singleton {
private Singleton() { }
private static class Holder{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return Holder.instance;
}
}
- 构造方法私有,确保外部不能通过new创建对象
- 提供公共的静态方法
二、结构型
(一)适配器模式
将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)
- 默认适配器
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。因此也称为单接口适配器模式。
// 适配者
public interface Adaptee {
void method1();
void method2();
void method3();
}
// 默认适配器
public class DefaultAdapter implements Adaptee{
@Override
public void method1() {
}
@Override
public void method2() {
}
@Override
public void method3() {
}
}
public class Target extends DefaultAdapter{
@Override
public void method1() {
System.out.println("default method1");
}
}
public class Test {
public static void main(String[] args) {
Target target = new Target();
target.method1();
}
}
- 类适配器
适配器类实现了目标抽象类接口并继承了适配者类,并在目标抽象类的实现方法中调用所继承的适配者类的方法。
通过实现接口或者继承
public interface Target {
void method1();
void method2();
void method3();
}
public class Adaptee {
public void method1(){
System.out.println("method1");
}
public void method2(){
System.out.println("method2");
}
}
public class Adapter extends Adaptee implements Target{
@Override
public void method3() {
System.out.println("adapter method3");
}
}
public class Test {
public static void main(String[] args) {
Target t = new Adapter();
t.method1(); // 通过继承获取
t.method2(); // 通过继承获取
t.method3(); // 自己实现的
}
}
- 对象适配器
在对象适配器模式中,适配器类继承了目标抽象类并定义了一个适配者类的对象实例,在所继承的目标抽象类方法中调用适配者类的相应业务方法。
public interface Target {
void method();
}
public class Adaptee {
public void method(){
System.out.println("method");
}
}
public class Adapter implements Target{
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
@Override
public void method() {
this.adaptee.method();
}
}
public static void main(String[] args) {
Target t = new Adapter(new Adaptee());
t.method();
}
(二)代理模式
给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
public interface Subject {
void doSome();
}
public class SubjectImpl implements Subject{
@Override
public void doSome() {
System.out.println("SubjectImpl do some");
}
}
public class Proxy implements Subject{
private Subject target = new SubjectImpl();
@Override
public void doSome() {
target.doSome();
}
}
public static void main(String[] args) {
Subject proxy = new Proxy();
proxy.doSome();
}
动态代理
- 动态代理是一种较为高级的代理模式,它的典型应用就是Spring AOP。
- 在传统的代理模式中,客户端通过Proxy调用SubjectImpl类的doSome()方法,同时还在代理类中封装了其他方法,可以处理一些其他问题。
- 如果按照这种方法使用代理模式,那么真实主题角色必须是事先已经存在的,并将其作为代理对象的内部成员属性。如果一个真实主题角色必须对应一个代理主题角色,这将导致系统中的类个数急剧增加,因此需要想办法减少系统中类的个数,此外,如何在事先不知道真实主题角色的情况下使用代理主题角色,这都是动态代理需要解决的问题。
(三)桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立地变化
多个变化维度,每个维度都抽象化,依靠具体的实现去组合,其中一个充当桥梁
// Level充当桥梁 ,有Info Debug Warn Error 实现类
public interface Level {
void log(String msg);
}
public class Info implements Level{
@Override
public void log(String msg) {
System.out.println("info "+msg);
}
}
public class Debug implements Level{
@Override
public void log(String msg) {
System.out.println("debug "+msg);
}
}
public class Warn implements Level{
@Override
public void log(String msg) {
System.out.println("warn "+msg);
}
}
public class Error implements Level{
@Override
public void log(String msg) {
System.out.println("error "+msg);
}
}
// Appender 的实现类,包含Level实例
public abstract class Appender {
protected Level level;
protected Appender(Level level){
this.level = level;
}
abstract void log(String msg);
}
public class ConsoleAppender extends Appender{
protected ConsoleAppender(Level level) {
super(level);
}
@Override
void log(String msg) {
super.level.log(msg);
}
}
public class DatabaseAppender extends Appender{
protected DatabaseAppender(Level level) {
super(level);
}
@Override
void log(String msg) {
super.level.log(msg);
}
}
public class FileAppender extends Appender{
protected FileAppender(Level level) {
super(level);
}
@Override
void log(String msg) {
super.level.log(msg);
}
}
// Appender和Level自由组合
public static void main(String[] args) {
ConsoleAppender consoleAppender = new ConsoleAppender(new Info());
ConsoleAppender consoleAppender1 = new ConsoleAppender(new Error());
FileAppender fileAppender = new FileAppender(new Info());
DatabaseAppender databaseAppender = new DatabaseAppender(new Debug());
String msg = "bridge pattern";
consoleAppender.log(msg);
consoleAppender1.log(msg);
fileAppender.log(msg);
databaseAppender.log(msg);
}
- 分离抽象接口及其实现部分。
- 桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差,而且多继承结构中类的个数非常庞大,桥接模式是比多继承方案更好的解决方法。
- 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
- 实现细节对客户透明,可以对用户隐藏实现细节。
(四)装饰模式
动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。
适合给一个对象增加多个小功能。
// 目标类,有两个实现类BlueDrink RedDrink
public interface Drinks {
String getDesc();
BigDecimal getPrice();
}
public class BlueDrink implements Drinks{
@Override
public String getDesc() {
return "蓝色饮料";
}
@Override
public BigDecimal getPrice() {
return BigDecimal.valueOf(20);
}
}
public class RedDrink implements Drinks{
@Override
public String getDesc() {
return "红色饮料";
}
@Override
public BigDecimal getPrice() {
return BigDecimal.valueOf(10);
}
}
// 装饰器,需要实现目标类的所有方法
public abstract class DrinkDecorator implements Drinks{
// 这里需要传入目标类,方便对齐进行增强
protected Drinks drinks;
protected DrinkDecorator(Drinks drinks){
this.drinks = drinks;
}
}
// 三个装饰器
public class CoffeeDecorator extends DrinkDecorator{
public CoffeeDecorator(Drinks drinks) {
super(drinks);
}
@Override
public String getDesc() {
return super.drinks.getDesc()+" + 咖啡";
}
@Override
public BigDecimal getPrice() {
return new BigDecimal(2).add(super.drinks.getPrice());
}
}
public class SaltDecorator extends DrinkDecorator{
public SaltDecorator(Drinks drinks) {
super(drinks);
}
@Override
public String getDesc() {
return super.drinks.getDesc()+" + 盐";
}
@Override
public BigDecimal getPrice() {
return new BigDecimal(0.5).add(super.drinks.getPrice());
}
}
public class SugurDecorator extends DrinkDecorator{
public SugurDecorator(Drinks drinks) {
super(drinks);
}
@Override
public String getDesc() {
return super.drinks.getDesc()+" + 糖";
}
@Override
public BigDecimal getPrice() {
return new BigDecimal(1).add(super.drinks.getPrice());
}
}
public class Test {
public static void main(String[] args) {
Drinks drinks = new CoffeeDecorator(new SugurDecorator(new RedDrink()));
System.out.println(drinks.getDesc()+" "+drinks.getPrice());
}
}
- 与继承关系相比,关联关系的主要优势在于不会破坏类的封装性,而且继承是一种耦合度较大的静态关系,无法在程序运行时动态扩展。在软件开发阶段,关联关系虽然不会比继承关系减少编码量,但是到了软件维护阶段,由于关联关系使系统具有较好的松耦合性,因此使得系统更加容易维护。当然,关联关系的缺点是比继承关系要创建更多的对象。
- 使用装饰模式来实现扩展比继承更加灵活,它以对客户透明的方式动态地给一个对象附加更多的责任。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。
(五)门面模式
外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
public interface Shape {
void draw();
}
public class CircleShape implements Shape{
@Override
public void draw() {
System.out.println("Circle::draw");
}
}
public class RectangleShape implements Shape{
@Override
public void draw() {
System.out.println("Retangle::draw");
}
}
public class ShapeFacade {
private Shape circleShape;
private Shape retanglesShape;
public ShapeFacade() {
this.circleShape = new CircleShape();
this.retanglesShape = new RectangleShape();
}
public void drawCircle(){
circleShape.draw();
}
public void drawRetangle(){
retanglesShape.draw();
}
}
public static void main(String[] args) {
ShapeFacade facade = new ShapeFacade();
facade.drawCircle();
facade.drawRetangle();
}
门面模式的优点
- 对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易。通过引入外观模式,客户代码将变得很简单,与之关联的对象也很少。
- 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。
- 降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
- 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。
门面模式的缺点
- 不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。
- 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
(六)享元模式
(七)组合模式
三、行为型
(一)策略模式
完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务
public interface Strategy {
void draw();
}
public class RedPen implements Strategy{
@Override
public void draw() {
System.out.println("redpen::draw");
}
}
public class BluePen implements Strategy{
@Override
public void draw() {
System.out.println("bluepen::draw");
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void executeDraw(){
this.strategy.draw();
}
}
public static void main(String[] args) {
Context context = new Context(new RedPen());
context.executeDraw();
context = new Context(new BluePen());
context.executeDraw();
}
(二)观察者模式
定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
// 被观察者
public class Subject {
private int state;
// 保存所有的观察者
private List<Observer> observers = new ArrayList<>();
public void registerObserver(Observer observer){
this.observers.add(observer);
}
public void setState(int state){
this.state = state;
this.notifyObserver();
}
private void notifyObserver(){
for (Observer observer : observers) {
observer.onUpdate();
}
}
}
// 观察者
public abstract class Observer {
protected Subject subject;
abstract void onUpdate();
}
public class Observer1 extends Observer{
public Observer1(Subject subject) {
this.subject = subject;
this.subject.registerObserver(this);
}
@Override
public void onUpdate() {
System.out.println("observer1 on update");
}
}
public class Observer2 extends Observer{
public Observer2(Subject subject) {
this.subject = subject;
this.subject.registerObserver(this);
}
@Override
public void onUpdate() {
System.out.println("observer2 on update");
}
}
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer1 = new Observer1(subject);
Observer observer2 = new Observer2(subject);
subject.setState(2);
}
观察者模式的核心是,一定有个地方存放了所有的观察者,当事件发生的时候,遍历观察者,调用他们的回调函数。
(三)责任链模式
通常建立一个单向链表,调动头部就可以,后面会自动流转起来。
public class Context {
private Boolean isNewUser;
private Boolean isLimit;
private Boolean isStock;
public Context(Boolean isNewUser, Boolean isLimit, Boolean isStock) {
this.isNewUser = isNewUser;
this.isLimit = isLimit;
this.isStock = isStock;
}
}
public abstract class RuleHandler {
protected RuleHandler successor;
public abstract void apply(Context context);
public void setSuccessor(RuleHandler successor){
this.successor = successor;
}
public RuleHandler getSuccessor(){
return this.successor;
}
}
public class NewUserHandler extends RuleHandler{
@Override
public void apply(Context context) {
if (context.getNewUser()){
// do sth
if (null != this.getSuccessor()){
this.getSuccessor().apply(context);
}
}else {
throw new RuntimeException("不是新用户");
}
}
}
public class LimitUserHandler extends RuleHandler{
@Override
public void apply(Context context) {
if (context.getLimit()){
// do sth
if (null != this.getSuccessor()){
this.getSuccessor().apply(context);
}
}else {
throw new RuntimeException("不在限定范围内");
}
}
}
public class StockUserHandler extends RuleHandler{
@Override
public void apply(Context context) {
if (context.getStock()){
// do sth
if (null != this.getSuccessor()){
this.getSuccessor().apply(context);
}
}else {
throw new RuntimeException("库存不足");
}
}
}
public static void main(String[] args) {
Context context = new Context(true,true,false);
NewUserHandler newUserHandler = new NewUserHandler();
LimitUserHandler limitUserHandler = new LimitUserHandler();
StockUserHandler stockUserHandler = new StockUserHandler();
limitUserHandler.setSuccessor(stockUserHandler);
newUserHandler.setSuccessor(limitUserHandler);
newUserHandler.apply(context);
}
(四)模板方法模式
在含有继承结构的代码中,模板方法非常好用
public abstract class Template {
// 最后需要执行的方法
public void execute() {
start();
run();
end();
}
// 留着子类去实现
protected abstract void start();
protected abstract void run();
protected abstract void end();
}
public class ConcreteTemplate extends Template{
@Override
protected void start() {
System.out.println("ConcreteTemplate start");
}
@Override
protected void run() {
System.out.println("ConcreteTemplate run");
}
@Override
protected void end() {
System.out.println("ConcreteTemplate end");
}
}
public static void main(String[] args) {
ConcreteTemplate template = new ConcreteTemplate();
template.execute();
}