设计模式总结

design pattern

Posted by Jay on March 17, 2019

设计模式总结

一、设计原则

1.开闭原则

对扩展开放,对修改关闭。面向抽象编程。

2.依赖倒置原则

高层模块不应该依赖底层模块,两者都应该依赖其抽象。面向接口编程。

3.单一职责原则

一个类/接口/方法只有一种引起它变更的原因,要求接口、方法做到单一职责原则。

4.接口隔离原则

接口拆分要适度。

5.迪米特法则(最少知道原则)

一个对象应该对其他对象保持最少的了解,尽量降低类与类之间的耦合性。

6.里式替换原则

所有引用基类(父类)的地方必须能透明地使用其子类的对象。

7.合成/复用原则(组合/复用原则)

尽量使用对象组合,而不是继承来达到复用的目的。

二、创建型

1.简单工厂模式

简单工厂模式通常是一个工厂类 XxxFactory,里面有一个(静态)方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。

(1)实例
public abstract class Video {
    public abstract void produce();
}
public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Java课程视频");
    }
}
public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Python课程视频");
    }
}

// 简单工厂
public class VideoFactory {
    // 使用反射,便与扩展
    public Video getVideo(Class<? extends Video> clazz) {
        Video video = null;
        try {
            video = (Video) Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return video;
    }

    public Video getVideo(String type) {
        if ("java".equalsIgnoreCase(type)) {
            return new JavaVideo();
        } else if ("python".equalsIgnoreCase(type)) {
            return new PythonVideo();
        } else {
            return null;
        }
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
//        VideoFactory videoFactory = new VideoFactory();
//        Video video = videoFactory.getVideo("java");
//        video.produce();

        VideoFactory videoFactory = new VideoFactory();
        Video video = videoFactory.getVideo(PythonVideo.class);
        if (video == null) {
            return;
        }
        video.produce();
    }
}
(2)应用

java.util.Calendar.createCalendar方法中的简单工厂应用:

// 代码片段
Calendar cal = null;

if (aLocale.hasExtensions()) {
    String caltype = aLocale.getUnicodeLocaleType("ca");
    if (caltype != null) {
        switch (caltype) {
        case "buddhist":
        cal = new BuddhistCalendar(zone, aLocale);
            break;
        case "japanese":
            cal = new JapaneseImperialCalendar(zone, aLocale);
            break;
        case "gregory":
            cal = new GregorianCalendar(zone, aLocale);
            break;
        }
    }
}
if (cal == null) {
    if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
        cal = new BuddhistCalendar(zone, aLocale);
    } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
               && aLocale.getCountry() == "JP") {
        cal = new JapaneseImperialCalendar(zone, aLocale);
    } else {
        cal = new GregorianCalendar(zone, aLocale);
    }
}
return cal;
2.工厂方法模式

定义一个创建对象的接口,但让实现这个接口的类决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。适用于同一产品等级。

(1)实例
public abstract class Video {
    public abstract void produce();
}
// 创建对象的接口
public abstract class VideoFactory {
    public abstract Video geVideo();
}

public class FEVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制FE课程视频");
    }
}
public class FEVideoFactory extends VideoFactory {
    @Override
    public Video geVideo() {
        return new FEVideo();
    }
}
public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Java课程视频");
    }
}
public class JavaVideoFactory extends VideoFactory {
    @Override
    public Video geVideo() {
        return new JavaVideo();
    }
}
// 测试
// 同一产品等级,使用工厂方法
public class Test {
    public static void main(String[] args) {
        VideoFactory videoFactory = new JavaVideoFactory();
        VideoFactory videoFactory2 = new FEVideoFactory();
        Video video = videoFactory.geVideo();
        video.produce();
    }
}
(2)应用

slf4j与logback:

工厂方法:org.slf4j.ILoggerFactory.getLogger

// slf4j
public interface ILoggerFactory {
    public Logger getLogger(String name);
}

工厂实现:ch.qos.logback.classic.LoggerContext

// logback
public final Logger getLogger(final String name) {

    //...
    if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
        return root;
    }

    int i = 0;
    Logger logger = root;

    Logger childLogger = (Logger) loggerCache.get(name);
    if (childLogger != null) {
        return childLogger;
    }

    String childName;
    while (true) {
        int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
        if (h == -1) {
            childName = name;
        } else {
            childName = name.substring(0, h);
        }
        i = h + 1;
        synchronized (logger) {
            childLogger = logger.getChildByName(childName);
            if (childLogger == null) {
                childLogger = logger.createChildByName(childName);
                loggerCache.put(childName, childLogger);
                incSize();
            }
        }
        logger = childLogger;
        if (h == -1) {
            return childLogger;
        }
    }
}

抽象产品:org.slf4j.Logger

具体产品:ch.qos.logback.classic.Logger

3.抽象工厂模式

抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口。(产品族)

(1)实例
// 抽象工厂
public interface CourseFactory {
    Video getVideo(); // 获取视频
    Article getArticle(); // 获取手记
}
public abstract class Video {
    public abstract void produce();
}
public abstract class Article {
    public abstract void produce();
}
public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Java课程视频");
    }
}
public class JavaArticle extends Article {
    @Override
    public void produce() {
        System.out.println("录制Java课程手记");
    }
}
public class JavaCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }

    @Override
    public Article getArticle() {
        return new JavaArticle();
    }
}
public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Python课程视频");
    }
}
public class PythonArticle extends Article {
    @Override
    public void produce() {
        System.out.println("录制Python课程手记");
    }
}
public class PythonCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }

    @Override
    public Article getArticle() {
        return new PythonArticle();
    }
}
// 同一产品簇,使用抽象工厂
public class Test {
    public static void main(String[] args) {
        CourseFactory courseFactory = new JavaCourseFactory();
        Video video = courseFactory.getVideo();
        Article article = courseFactory.getArticle();
        video.produce();
        article.produce();
    }
}
(2)应用

org.apache.ibatis.session.SqlSessionFactory:

public interface SqlSessionFactory {

  SqlSession openSession(); // 获取SqlSession

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration(); // 获取配置

}
4.建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。用户只需指定需要创建的类型就可以得到它们,建造过程和细节不需要知道。

(1)实例
import lombok.Builder;

// 建造者设计模式
//@Builder
public class User {
    private String name;
    private String password;
    private String nickname;
    private int age;

    private User(String name, String password, String nickname, int age) {
        this.name = name;
        this.password = password;
        this.nickname = nickname;
        this.age = age;
    }
		// Builder
    public static UserBuilder builder() {
        return new UserBuilder();
    }

    public static class UserBuilder {
        private String name;
        private String password;
        private String nickname;
        private int age;

        private UserBuilder() {
        }

        public UserBuilder name(String name) {
            this.name = name;
            return this;
        }

        public UserBuilder password(String password) {
            this.password = password;
            return this;
        }

        public UserBuilder nickname(String nickname) {
            this.nickname = nickname;
            return this;
        }

        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }

        public User build() {
            if (name == null || password == null) {
                throw new RuntimeException("用户名和密码必填");
            }
            if (age <= 0 || age >= 150) {
                throw new RuntimeException("年龄不合法");
            }
            // 还可以做赋予”默认值“的功能
            if (nickname == null) {
                nickname = name;
            }
            return new User(name, password, nickname, age);
        }
    }

}

public class Test {
    public static void main(String[] args){
        User u = User.builder()
                .name("foo")
                .age(25)
                .password("pass12345")
                .build();

    }
}
(2)应用
  • JDK:
    • StringBuilder
    • StringBuffer
  • Guava:
    • ImmutableSet
    • CacheBuilder
5.单例模式
(1)懒汉式1
// 同步锁synchronized
public class LazySingleton {
    private static LazySingleton instance = null;

    private LazySingleton() {
        // 无法阻止反射攻击
        if (instance != null) {
            throw new RuntimeException("单例构造器禁用反射调用");
        }
    }

    public synchronized static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
(2)懒汉式2
// 双重检查+volatile
public class LazyDoubleCheckSingleton {
    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;

    private LazyDoubleCheckSingleton() {

    }

    public static LazyDoubleCheckSingleton getInstance() {
        if (lazyDoubleCheckSingleton == null) {
            synchronized (LazyDoubleCheckSingleton.class) {
                if (lazyDoubleCheckSingleton == null) {
                    lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
                    //1.分配内存给这个对象
//                  //3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
                    //2.初始化对象
//                    intra-thread semantics
//                    ---------------//3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
                }
            }
        }
        return lazyDoubleCheckSingleton;
    }
}
(3)静态嵌套类
// 静态嵌套类单例
public class StaticNestedClassSingleton {

    // 静态嵌套类可以访问外围类的静态属性和方法
    private static class StaticNestedClass {
        private static StaticNestedClassSingleton staticNestedClassSingleton = new StaticNestedClassSingleton();
    }

    public static StaticNestedClassSingleton getInstance() {
        return StaticNestedClass.staticNestedClassSingleton; // 初始化
    }

    private StaticNestedClassSingleton() {
        // 防止反射攻击
        if (StaticNestedClass.staticNestedClassSingleton != null) {
            throw new RuntimeException("单例构造器禁用反射调用");
        }
    }

}
(4)饿汉式
// 饿汉式单例
public class HungrySingleton implements Serializable, Cloneable {
    private static final HungrySingleton instance;

    static {
        instance = new HungrySingleton();
    }

    public static HungrySingleton getInstance() {
        return instance;
    }

    private HungrySingleton() {
        // 防止反射攻击
        if (instance != null) {
            throw new RuntimeException("单例构造器禁用反射调用");
        }
    }

    // 防止序列化与反序列化破坏单例模式
    private Object readResolve() {
        return instance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
        return getInstance();
    }
}
(5)容器单例
// 容器单例,非线程安全。适合在类初始化的时候使用,维护很多单例
public class ContainerSingleton {

    private ContainerSingleton() {

    }

    private static Map<String, Object> singletonMap = new HashMap<>();

    public static void putInstance(String key, Object instance) {
        if (StringUtils.isNotBlank(key) && instance != null) {
            if (!singletonMap.containsKey(key)) {
                singletonMap.put(key, instance);
            }
        }
    }

    public static Object getInstance(String key) {
        return singletonMap.get(key);
    }

}
(6)枚举单例
// 枚举单例
public enum EnumSingleton {
    INSTANCE{
        @Override
        protected void printTest() {
            System.out.println("print test jat,,,");
        }
    };

    protected abstract void printTest();

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance() {
        return INSTANCE;
    }

}
(7)ThreadLocalSingleton
// 线程内单例
public class ThreadLocalSingleton {
    private static final ThreadLocal<ThreadLocalSingleton> THREAD_LOCAL_SINGLETON_THREAD_LOCAL
            = new ThreadLocal<ThreadLocalSingleton>() {
        @Override
        protected ThreadLocalSingleton initialValue() {
            return new ThreadLocalSingleton();
        }
    };

    private ThreadLocalSingleton() {

    }

    public static ThreadLocalSingleton getInstance() {
        return THREAD_LOCAL_SINGLETON_THREAD_LOCAL.get();
    }

}
(8)应用

java.lang.Runtime.getRuntime 饿汉式

public class Runtime {
    private static Runtime currentRuntime = new Runtime();
 
  	private Runtime() {}
  
    public static Runtime getRuntime() {
        return currentRuntime;
    }
}
6.原型模式

原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

(1)实例
// 抽象类
public abstract class A implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

// 实现类
public class B extends A {
    public static void main(String[] args) throws CloneNotSupportedException {
        B b = new B();
        B b2 = (B) b.clone();
        System.out.println(b);
        System.out.println(b2);
    }
}
// 深拷贝与浅拷贝
public class Pig implements Cloneable {
    private String name;
    private Date birthday;

    public Pig(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Pig{" +
                "name='" + name + '\'' +
                ", birthday=" + birthday +
                '}' + "--" + super.toString();
    }

    // 浅拷贝
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
//    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 深拷贝
        Pig pig = (Pig) super.clone();
        pig.birthday = (Date) pig.birthday.clone();
        return pig;
    }
}
(2)应用

ArrayList:

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size); // 元素引用相同
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

三、结构型

1.外观模式

又叫门面模式,提供了一个统一的接口(外观类),用来访问子系统的一群接口。包含外观类、子系统、客户端三部分。

(1)实例
// 积分兑换的礼物
public class PointGift {
    private String name;

    public PointGift(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

// 校验子系统
public class QualifyService {
    public boolean isAvailable(PointGift pointGift) {
        System.out.println("校验 " + pointGift.getName() + " 积分资格通过, 库存通过");
        return true;
    }
}

// 扣减积分子系统
public class PointPaymentService {
    public boolean pay(PointGift pointGift) {
        // 扣减积分
        System.out.println("支付 " + pointGift.getName() + " 积分成功");
        return true;
    }
}

// 物流子系统
public class ShippingService {
    public String shipGift(PointGift pointGift) {
        // 物流系统的对接逻辑
        System.out.println(pointGift.getName() + " 进入物流系统");
        String shippingOrderNo = "666";
        return shippingOrderNo;
    }
}

// 外观类
public class GiftExchangeService {
    private QualifyService qualifyService = new QualifyService();
    private PointPaymentService pointPaymentService = new PointPaymentService();
    private ShippingService shippingService = new ShippingService();

    public void giftExchange(PointGift pointGift) {
        if (qualifyService.isAvailable(pointGift)) {
            // 资格校验通过
            if (pointPaymentService.pay(pointGift)) {
                // 积分支付通过
                String shippingOrderNo = shippingService.shipGift(pointGift);
                System.out.println("物流系统下单成功,订单号是: " + shippingOrderNo);
            }
        }
    }

}

// 客户端
public class Test {
    public static void main(String[] args) {

        PointGift pointGift = new PointGift("T恤");
        // 外观对象
        GiftExchangeService giftExchangeService = new GiftExchangeService();

        giftExchangeService.giftExchange(pointGift);

    }
}
(2)应用

org.springframework.jdbc.support.JdbcUtils:

public static void closeConnection(Connection con) {
   if (con != null) {
      try {
         con.close();
      }
      catch (SQLException ex) {
         logger.debug("Could not close JDBC Connection", ex);
      }
      catch (Throwable ex) {
         // We don't trust the JDBC driver: It might throw RuntimeException or Error.
         logger.debug("Unexpected exception on closing JDBC Connection", ex);
      }
   }
}
2.装饰者模式

在不改变原有对象的基础上,将功能附加到对象之上。提供了比继承更具弹性的替代方案。(扩展了原有对象的功能)

(1)实例
// 抽象被装饰者
public abstract class ABattercake {
    protected abstract String getDesc();
    protected abstract int cost();
}

// 具体被装饰者
public class Battercake extends ABattercake {
    @Override
    protected String getDesc() {
        return "煎饼";
    }

    @Override
    protected int cost() {
        return 8;
    }
}

// 抽象装饰者
public abstract class AbstractDecorator extends ABattercake {

    private ABattercake aBattercake;

    public AbstractDecorator(ABattercake aBattercake) {
        this.aBattercake = aBattercake;
    }

    protected abstract void doSomething();

    @Override
    protected String getDesc() {
        return this.aBattercake.getDesc();
    }

    @Override
    protected int cost() {
        return this.aBattercake.cost();
    }
}

// 具体装饰者1
public class EggDecorator extends AbstractDecorator {
    public EggDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    protected void doSomething() {

    }

    @Override
    protected String getDesc() {
        return super.getDesc() + ", 加鸡蛋";
    }

    @Override
    protected int cost() {
        return super.cost() + 1;
    }
}

// 具体装饰者2
public class SausageDecorator extends AbstractDecorator {
    public SausageDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    protected void doSomething() {

    }

    @Override
    protected String getDesc() {
        return super.getDesc() + ", 加香肠";
    }

    @Override
    protected int cost() {
        return super.cost() + 2;
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        ABattercake aBattercake = new Battercake(); 
        aBattercake = new EggDecorator(aBattercake); // 加鸡蛋
        aBattercake = new EggDecorator(aBattercake); // 加鸡蛋
        aBattercake = new SausageDecorator(aBattercake); // 再加香肠
        System.out.println(aBattercake.getDesc() + " 销售价格: " + aBattercake.cost());
    }
}
// 煎饼, 加鸡蛋, 加鸡蛋, 加香肠 销售价格: 12

UML图:

(2)应用

Java IO中的装饰者模式应用:

DataInputStream is = new DataInputStream(
                              new BufferedInputStream(
                                  new FileInputStream("demo.txt")));
3.适配器模式

将一个类的接口转换成客户期望的另一个借口。使原本不兼容的类可以一起工作。有默认适配器、类适配器和对象适配器三种。

(1)默认适配器
// 目标接口,方法太多
public interface FileAlterationListener {
    void onStart(final FileAlterationObserver observer);

    void onDirectoryCreate(final File directory);

    void onDirectoryChange(final File directory);

    void onDirectoryDelete(final File directory);

    void onFileCreate(final File file);

    void onFileChange(final File file);

    void onFileDelete(final File file);

    void onStop(final FileAlterationObserver observer);
}

// 默认适配器,实现所有接口方法,方法体为空
public class FileAlterationListenerAdapter implements FileAlterationListener {
    @Override
    public void onStart(FileAlterationObserver observer) {

    }

    @Override
    public void onDirectoryCreate(File directory) {

    }

    @Override
    public void onDirectoryChange(File directory) {

    }

    @Override
    public void onDirectoryDelete(File directory) {

    }

    @Override
    public void onFileCreate(File file) {

    }

    @Override
    public void onFileChange(File file) {

    }

    @Override
    public void onFileDelete(File file) {

    }

    @Override
    public void onStop(FileAlterationObserver observer) {

    }
}

// 接口实现类按需重写Adapter类方法
public class FileMonitor extends FileAlterationListenerAdapter {
    @Override
    public void onFileCreate(File file) {
        // 文件创建
    }

    @Override
    public void onFileDelete(File file) {
        // 文件删除
    }
}
(2)类适配器
// 被适配者
public class Adaptee {
    public void adapteeRequest() {
        System.out.println("被适配者的方法");
    }
}

// 目标
public interface Target {
    void request();
}

// 类适配器,通过类继承的方式
public class Adapter extends Adaptee implements Target {
    @Override
    public void request() {
        // do something else...
        super.adapteeRequest();
        // do something else...
    }
}
(3)对象适配器
// 被适配者
public class Adaptee {
    public void adapteeRequest() {
        System.out.println("被适配者的方法");
    }
}

// 目标
public interface Target {
    void request();
}

// 对象适配器,通过对象组合的方式
public class Adapter implements Target {
    // 对象组合
    private Adaptee adaptee = new Adaptee();

    @Override
    public void request() {
        // do something else...
        adaptee.adapteeRequest();
        // do something else...
    }
}

(4)应用
// Executors方法,将Runnable实例适配成Callable实例
public static Callable<Object> callable(Runnable task) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<Object>(task, null);
}

static final class RunnableAdapter<T> implements Callable<T> {
  	final Runnable task;
  	final T result;
  	RunnableAdapter(Runnable task, T result) {
   	 	this.task = task;
   	 	this.result = result;
  	}
  	public T call() {
    		task.run();
    		return result;
  	}	
}
4.享元模式(对象复用)

提供了减少对象数量从而改善应用所需的对象结构的方式。减少对象的创建(缓存),降低内存中对象的数量。

(1)实例
// 员工
public interface Employee {
    void report();
}

// 经理
public class Manager implements Employee {
    @Override
    public void report() {
        System.out.println(reportContent);
    }

    // 内部状态
    private String title = "部门经理";

    // 外部状态
    private String reportContent;
    private String department;

    public Manager(String department) {
        this.department = department;
    }

    public void setReportContent(String reportContent) {
        this.reportContent = reportContent;
    }
}

// 员工工厂,简单工厂
public class EmployeeFactory {
		// 容器单例
    private static final Map<String, Employee> EMPLOYEE_MAP = new HashMap<>(16);

    public static Employee getManager(String department) {
        Manager manager = (Manager) EMPLOYEE_MAP.get(department);
        if (manager == null) {
            manager = new Manager(department);
            System.out.print("创建部门经理:" + department);
            String reportContent = department+"部门汇报:此次报告的主要内容是......";
            manager.setReportContent(reportContent);
            System.out.println(" 创建报告:" + reportContent);
            EMPLOYEE_MAP.put(department, manager);
        }
        return manager;
    }

}
(2)应用

java.lang.Integer.valueOf(int)

// 首先判断i是否在-128到127之间,是则从缓存中取出Integer对象;否则创建对象
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
5.组合模式

将对象组合成树形结构以表示”部分—整体”的层次结构。组合模式使客户端对单个对象和组合对象保持一致的方式处理。(递归结构)

(1)实例
// 公共的抽象父类或接口
public abstract class CatalogComponent {
    public void add(CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持添加操作");
    }

    public void remove(CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持删除操作");
    }

    public String getName(CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持获取名称操作");
    }

    public double getPrice(CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持获取价格操作");
    }

    // 1 print方法不需要参数
    public void print() {
        throw new UnsupportedOperationException("不支持打印操作");
    }
}

// 目录课程
public class Course extends CatalogComponent {

    private String name;

    private double price;

    public Course(String name, double price) {
        this.name = name;
        this.price = price;
    }

    // 2 重写需要的方法
    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public double getPrice(CatalogComponent catalogComponent) {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println("Course name: " + name + ", Price: " + price);
    }

}

// 课程目录
public class CourseCatalog extends CatalogComponent {

    private List<CatalogComponent> components = new ArrayList<>();
    private String name;
    private Integer level; // 3 目录级别,控制缩进

    public CourseCatalog(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public void add(CatalogComponent catalogComponent) {
        components.add(catalogComponent);
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        components.remove(catalogComponent);
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public void print() {
        System.out.println(this.name);
        components.forEach(component -> {
            if (level != null) {
                for (Integer i = 0; i < level; i++) {
                    System.out.print("  ");
                }
            }
            component.print();
        });
    }
}

// 组合模式测试
public class Test {
    public static void main(String[] args) {

        CatalogComponent linuxCourse = new Course("Linux", 11);
        CatalogComponent windowsCourse = new Course("Windows", 11);

        CatalogComponent javaCourseCatalog = new CourseCatalog("Java课程目录", 2);

        CatalogComponent mmall1 = new Course("Java电商1期", 30);
        CatalogComponent mmall2 = new Course("Java电商2期", 30);
        CatalogComponent javaDesignPattern = new Course("Java设计模式", 40);

        javaCourseCatalog.add(mmall1);
        javaCourseCatalog.add(mmall2);
        javaCourseCatalog.add(javaDesignPattern);


        CatalogComponent imoocMainCatalog = new CourseCatalog("慕课网课程主目录", 1);
        imoocMainCatalog.add(linuxCourse);
        imoocMainCatalog.add(windowsCourse);
        imoocMainCatalog.add(javaCourseCatalog);

        imoocMainCatalog.print();
    }
}
// 输出
慕课网课程主目录
  Course name: Linux, Price: 11.0
  Course name: Windows, Price: 11.0
  Java课程目录
    Course name: Java电商1期, Price: 30.0
    Course name: Java电商2期, Price: 30.0
    Course name: Java设计模式, Price: 40.0
(2)应用

org.apache.ibatis.scripting.xmltags.MixedSqlNode

public class MixedSqlNode implements SqlNode {
  private List<SqlNode> contents;

  public MixedSqlNode(List<SqlNode> contents) {
    this.contents = contents;
  }

  @Override
  public boolean apply(DynamicContext context) {
    for (SqlNode sqlNode : contents) {
      sqlNode.apply(context);
    }
    return true;
  }
}
6.桥接模式

将抽象部分和它的具体实现部分分离,使他们都可以独立地变化。通过组合的方式建立两个类之间的联系,而不是继承。

(1)实例
// 具体实现
public interface DrawAPI {
    void draw(int radius, int x, int y);
}
public class GreenPen implements DrawAPI {
    @Override
    public void draw(int radius, int x, int y) {
        System.out.println("用绿色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);
    }
}
public class RedPen implements DrawAPI {
    @Override
    public void draw(int radius, int x, int y) {
        System.out.println("用红色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);
    }
}

// 抽象部分
public abstract class Shape {
    protected DrawAPI drawAPI; // 组合的方式

    protected Shape(DrawAPI drawAPI) {
        this.drawAPI = drawAPI;
    }

    protected abstract void draw();
}
// 圆
public class Circle extends Shape {

    private int radius;

    public Circle(int radius, DrawAPI drawAPI) {
        super(drawAPI);
        this.radius = radius;
    }

    @Override
    protected void draw() {
        System.out.println("画一个圆");
        drawAPI.draw(radius, 0, 0);
    }
}
// 长方形
public class Rectangle extends Shape {
    private int x;
    private int y;

    protected Rectangle(int x, int y, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;
        this.y = y;
    }

    @Override
    protected void draw() {
        System.out.println("画一个长方形");
        drawAPI.draw(0, x, y);
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        Shape greenCircle = new Circle(10, new GreenPen());
        greenCircle.draw();

        Shape redRectangle = new Rectangle(4, 8, new RedPen());
        redRectangle.draw();
    }
}
// 输出
画一个圆
用绿色笔画图radius:10, x:0, y:0
画一个长方形
用红色笔画图radius:0, x:4, y:8
(2)应用

JDBC java.sql.DriverManager

private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
DriverInfo---java.sql.Driver 不同厂商不同的Driver实现DriverManager 与Driver是桥接模式
7.代理模式

分为静态代理和动态代理。

(1)准备场景
// 订单
public class Order {
    private Object orderInfo;
    private int userId;

    public Object getOrderInfo() {
        return orderInfo;
    }

    public void setOrderInfo(Object orderInfo) {
        this.orderInfo = orderInfo;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }
}

// 订单服务
public interface IOrderService {
    int saveOrder(Order order);
}
// 订单Dao
public interface IOrderDao {
    int insertOrder(Order order);
}
// 订单服务实现
public class OrderServiceImpl implements IOrderService {
    // Spring注入
    private IOrderDao orderDao;

    @Override
    public int saveOrder(Order order) {
        System.out.println("OrderService调用OrderDao,将Order保存到数据库");
        // Spring注入,这里直接new
        orderDao = new OrderDaoImpl();
        return orderDao.insertOrder(order);
    }
}
// OrderDao实现
public class OrderDaoImpl implements IOrderDao {
    @Override
    public int insertOrder(Order order) {
        System.out.println("OrderDao插入Order到数据库成功");
        return 1;
    }
}

public class DataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOOLDER = new ThreadLocal<>();

    public static void setDBtype(String dbType) {
        CONTEXT_HOOLDER.set(dbType);
    }

    public strictfp String getDBType() {
        return CONTEXT_HOOLDER.get();
    }

    public static void clearDBType() {
        CONTEXT_HOOLDER.remove();
    }

}
(2)静态代理
// OrderService静态代理
public class OrderServiceStaticProxy implements IOrderService {

    private IOrderService orderService;

    public OrderServiceStaticProxy(IOrderService orderService) {
        this.orderService = orderService;
    }

    @Override
    public int saveOrder(Order order) {
        beforeMethod(order); // 增强
        int result = orderService.saveOrder(order);
        afterMethod(order); // 增强
        return result; 
    }

    private void beforeMethod(Order order) {
        int userId = order.getUserId();
        int daRouter = userId % 2;
        System.out.println("静态代理分配到[db" + daRouter + "]处理数据");

        // 设置DataSource
        DataSourceContextHolder.setDBtype("db" + daRouter);

        System.out.println("静态代理before code");
    }

    private void afterMethod(Order order) {
        System.out.println("静态代理after code");
    }
}

// 静态代理测试
public class Test {
    public static void main(String[] args) {
        Order order = new Order();
        order.setUserId(2);

        OrderServiceStaticProxy serviceStaticProxy = new OrderServiceStaticProxy(new OrderServiceImpl());
        serviceStaticProxy.saveOrder(order);
    }
}

(3)动态代理
// 动态代理handler,具有创建代理的功能
public class OrderServiceDynamicProxy implements InvocationHandler {
    // 被代理对象,OrderServiceImpl
    private Object target;

    public OrderServiceDynamicProxy(Object target) {
        this.target = target;
    }

    // 创建代理对象
    public Object build() {
        Class clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object arg = args[0];
        beforeMethod(arg); // 增强
        Object result = method.invoke(target, args);
        afterMethod(); // 增强
        return result;
    }

    private void beforeMethod(Object arg) {
        System.out.println("动态代理before code");
        int userId = 0;
        if (arg instanceof Order) {
            userId = ((Order) arg).getUserId();
        }
        int daRouter = userId % 2;
        System.out.println("动态代理分配到[db" + daRouter + "]处理数据");

        // 设置DataSource
        DataSourceContextHolder.setDBtype("db" + daRouter);
    }

    private void afterMethod() {
        System.out.println("动态代理after code");
    }
}

// 动态代理测试
public class Test {
    public static void main(String[] args) {
        Order order = new Order();
//        order.setUserId(1);
        order.setUserId(2);
				// 创建代理
        IOrderService orderService = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).build();
        orderService.saveOrder(order);
    }
}

四、行为型

行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰。

1.模板方法模式

定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。

(1)实例
// 模板
public abstract class AbstractCourse {
    // 算法流程固定,不允许修改 final
    protected final void makeCourse() {
        this.makePPT();
        this.makeVedio();
        if (needWriteArticle()) { // 控制
            this.writeActicle();
        }
        packageCourse(); // 完全由子类实现
    }

    final void makePPT() {
        System.out.println("制作PPT");
    }

    final void makeVedio() {
        System.out.println("制作视频");
    }

    // 钩子方法
    final void writeActicle() {
        System.out.println("写手记");
    }
    protected boolean needWriteArticle() {
        return false;
    }

    protected abstract void packageCourse();
}

// 设计模式课程,课程级别
public class DesignPatternCourse extends AbstractCourse {

    @Override
    protected void packageCourse() {
        System.out.println("提供课程Java源代码");
    }

    @Override
    protected boolean needWriteArticle() {
        return true;
    }
}
// 前端课程,大范围
public class FECourse extends AbstractCourse {
    private boolean needWriteArticleFlag = false;

    public FECourse(boolean needWriteArticleFlag) {
        this.needWriteArticleFlag = needWriteArticleFlag;
    }

    @Override
    protected void packageCourse() {
        System.out.println("提供课程的前端代码");
        System.out.println("提供课程的图片等多媒体素材");
    }

    @Override
    protected boolean needWriteArticle() {
        return needWriteArticleFlag;
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println("后端设计模式课程start---");
        AbstractCourse designPatternCourse = new DesignPatternCourse();
        designPatternCourse.makeCourse();
        System.out.println("后端设计模式课程end---");

        System.out.println("-------------------------");

        System.out.println("前端课程start---");
        AbstractCourse feCourse = new FECourse(false);
        feCourse.makeCourse();
        System.out.println("前端课程end---");
    }
}
// 输出
后端设计模式课程start---
制作PPT
制作视频
写手记
提供课程Java源代码
后端设计模式课程end---
-------------------------
前端课程start---
制作PPT
制作视频
提供课程的前端代码
提供课程的图片等多媒体素材
前端课程end---
(2)应用
AbstractListAbstractMapAbstractSet

javax.servlet.http.HttpServlet--doGet() doPost()...

org.apache.ibatis.executor.BaseExecutor--doUpdate() doQuery()
2.迭代器模式

提供一种方法,顺序访问一个集合对象中的各个元素,而又不暴露该对象的内部表示。为遍历不同的集合结构提供统一的接口。

(1)实例
// 课程
public class Course {
    private String name;

    public Course(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

// 课程迭代器
public interface CourseIterator {
    boolean hasNextCourse();

    Course nextCourse();
}
public class CourseIteratorImpl implements CourseIterator {

    private List<Course> courses;

    private int position;

    public CourseIteratorImpl(List<Course> courses) {
        this.courses = courses;
    }

    @Override
    public boolean hasNextCourse() {
        return position < courses.size();
    }

    @Override
    public Course nextCourse() {
        System.out.println("返回课程,位置是: " + position);
        Course course = courses.get(position);
        position++;
        return course;
    }
}
// 课程集合
public interface CourseAggregate {
    void addCourse(Course course);

    void removeCourse(Course course);

    CourseIterator getCourseIterator();
}
public class CourseAggregateImpl implements CourseAggregate {

    private List<Course> courses;

    public CourseAggregateImpl() {
        this.courses = new ArrayList<>();
    }

    @Override
    public void addCourse(Course course) {
        courses.add(course);
    }

    @Override
    public void removeCourse(Course course) {
        courses.remove(course);
    }

    @Override
    public CourseIterator getCourseIterator() {
        return new CourseIteratorImpl(courses);
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        Course course1 = new Course("Java电商一期");
        Course course2 = new Course("Java电商二期");
        Course course3 = new Course("Java设计模式精讲");
        Course course4 = new Course("Python课程");
        Course course5 = new Course("算法课程");
        Course course6 = new Course("前端课程");


        CourseAggregate courseAggregate = new CourseAggregateImpl();

        courseAggregate.addCourse(course1);
        courseAggregate.addCourse(course2);
        courseAggregate.addCourse(course3);
        courseAggregate.addCourse(course4);
        courseAggregate.addCourse(course5);
        courseAggregate.addCourse(course6);

        System.out.println("-----课程列表-----");
        printCourses(courseAggregate);

        courseAggregate.removeCourse(course4);
        courseAggregate.removeCourse(course5);

        System.out.println("-----删除操作之后的课程列表-----");
        printCourses(courseAggregate);
    }

    public static void printCourses(CourseAggregate courseAggregate){
        CourseIterator courseIterator= courseAggregate.getCourseIterator();
        while(courseIterator.hasNextCourse()){
            Course course=courseIterator.nextCourse();
            System.out.println(course.getName());
        }
    }
}
// 输出
-----课程列表-----
返回课程,位置是: 0
,
返回课程,位置是: 1
Java电商二期
返回课程,位置是: 2
Java设计模式精讲
返回课程,位置是: 3
Python课程
返回课程,位置是: 4
算法课程
返回课程,位置是: 5
前端课程
-----删除操作之后的课程列表-----
返回课程,位置是: 0
,
返回课程,位置是: 1
Java电商二期
返回课程,位置是: 2
Java设计模式精讲
返回课程,位置是: 3
前端课程
(2)应用

java.util.ArrayList.Itr

java.util.ArrayList.ListItr

3.策略模式

定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化不会影响到使用算法的用户。

适用于替换if…else…

(1)实例
// 促销策略抽象
public interface PromotionStrategy {
    void doPromotion();
}
public class FanXianPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("返现促销,返回的金额存放到用户的余额中");
    }
}
public class LiJianPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("立减促销,课程的价格直接减去配置的价格");
    }
}
public class ManJianPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("满减促销,满200-20元");
    }
}
public class EmptyPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("无促销");
    }
}

// 促销活动,使用促销策略
public class PromotionActivity {
    private PromotionStrategy promotionStrategy;

    public PromotionActivity(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }

    public void executePromotionStrategy() {
        promotionStrategy.doPromotion();
    }
}

// 促销策略工厂
public class PromotionStrategyFactory {
    private static final Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP =
            new HashMap<>(8);

    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN, new FanXianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN, new LiJianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.MANJIAN, new ManJianPromotionStrategy());
    }

    private static final PromotionStrategy NON_PROMOTION = new EmptyPromotionStrategy();

    private PromotionStrategyFactory() {

    }

    public static PromotionStrategy getPromotionStrategy(String promotionKey) {
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
        return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
    }

    interface PromotionKey {
        String LIJIAN = "LIJIAN";
        String MANJIAN = "MANJIAN";
        String FANXIAN = "FANXIAN";
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        String promotionKey = "MANJIAN";

        PromotionActivity promotionActivity =
                new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));

        promotionActivity.executePromotionStrategy();
    }
}
(2)应用

比较器java.util.Comparator,不同比较器有不同的比较策略。

Spring资源抽象org.springframework.core.io.Resource

4.解释器模式

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。为了解释一种语言,而为语言创建的解释器。

(1)实例
// 解释器
public interface Interpreter {
    int interpret();
}
// 加法解释器
public class AddInterpreter implements Interpreter {
    private Interpreter firstExpression, secondExpresion;

    public AddInterpreter(Interpreter firstExpression, Interpreter secondExpresion) {
        this.firstExpression = firstExpression;
        this.secondExpresion = secondExpresion;
    }

    @Override
    public int interpret() {
        return firstExpression.interpret() + secondExpresion.interpret();
    }

    @Override
    public String toString() {
        return "+";
    }
}
// 乘法解释器
public class MultiInterpreter implements Interpreter {

    private Interpreter firstExpression, secondExpresion;

    public MultiInterpreter(Interpreter firstExpression, Interpreter secondExpresion) {
        this.firstExpression = firstExpression;
        this.secondExpresion = secondExpresion;
    }

    @Override
    public int interpret() {
        return firstExpression.interpret() * secondExpresion.interpret();
    }

    @Override
    public String toString() {
        return "*";
    }
}
// 空解释器
public class EmptyInterpreter implements Interpreter {
    @Override
    public int interpret() {
        return 0;
    }
}

// 数字
public class NumberInterpreter implements Interpreter {

    private int number;

    public NumberInterpreter(int number) {
        this.number = number;
    }

    public NumberInterpreter(String number) {
        this.number = Integer.parseInt(number);
    }

    @Override
    public int interpret() {
        return this.number;
    }
}

// 自定义表达式解析器
public class GeelyExpressionParser {

    private Stack<Interpreter> stack = new Stack<>();

    public int parse(String str) {
        String[] items = str.split(" ");
        for (String symbol : items) {
            if (!OperationUtil.isOperator(symbol)) {
                Interpreter numberExpression = new NumberInterpreter(symbol);
                stack.push(numberExpression);
                System.out.printf("入栈:%d\n", numberExpression.interpret());
            } else {
                Interpreter firstExpression = stack.pop();
                Interpreter secondExpression = stack.pop();
                System.out.printf("出栈:%d 和 %d\n", firstExpression.interpret(), secondExpression.interpret());
                Interpreter operator = OperationUtil.getExpressionObject(symbol, firstExpression, secondExpression);
                System.out.printf("应用运算符 %s\n", operator);
                int result = operator.interpret();
                NumberInterpreter numberExpression = new NumberInterpreter(result);
                stack.push(numberExpression);
                System.out.printf("阶段结果入栈:%d\n", numberExpression.interpret());
            }
        }
        return stack.pop().interpret();
    }

}

// 操作符工具类
public class OperationUtil {
    public static boolean isOperator(String symbol) {
        return "+".equals(symbol) || "*".equals(symbol);
    }

    public static Interpreter getExpressionObject(String symbol, Interpreter firstExpression, Interpreter secondExpression) {
        if ("*".equals(symbol)) {
            return new MultiInterpreter(firstExpression, secondExpression);
        } else if ("+".equals(symbol)) {
            return new AddInterpreter(firstExpression, secondExpression);
        } else {
            return new EmptyInterpreter();
        }
    }
}

// 解释器模式测试
public class Test {
    public static void main(String[] args) {
        String str = "6 100 11 + *";
        GeelyExpressionParser expressionParser = new GeelyExpressionParser();
        int result = expressionParser.parse(str);
        System.out.println("表达式计算结果:" + result);
    }
}
(2)应用

正则表达式抽象 java.util.regex.Pattern

Spring EL表达式抽象 org.springframework.expression.ExpressionParser

5.观察者模式

定义了对象之间的一对多依赖,让多个观察者对象同时监听某个主题对象,当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。

(1)实例
// 课程,被观察对象
public class Course extends Observable {
    private String courseName;

    public Course(String courseName) {
        this.courseName = courseName;
    }

    public String getCourseName() {
        return courseName;
    }

    public void produceQuestion(Course course, Question question) {
        System.out.println(question.getUsername() + "在" + course.getCourseName() + "提交了一个问题。");
        // 设置数据变化
        setChanged();
        // 通知观察者
        notifyObservers(question);
    }
}

// 讲师,观察者
public class Teacher implements Observer {
    private String teacherName;

    public Teacher(String teacherName) {
        this.teacherName = teacherName;
    }

    public String getTeacherName() {
        return teacherName;
    }

    @Override
    public void update(Observable o, Object arg) {
        Course course = (Course) o;
        Question question = (Question) arg;
        System.out.println(teacherName + "老师的" + course.getCourseName() + "课程收到了一个"
                + question.getUsername() + "提交的问题:" + question.getQuestionContent());
    }
}

// 提问题
public class Question {
    private String username;
    private String questionContent;

    public String getUsername() {
        return username;
    }

    public String getQuestionContent() {
        return questionContent;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setQuestionContent(String questionContent) {
        this.questionContent = questionContent;
    }
}

// 观察者模式测试
public class Test {
    public static void main(String[] args) {
        // 被观察者
        Course course = new Course("Java设计模式精讲");

        // 观察者
        Teacher teacher = new Teacher("Alpha");

        course.addObserver(teacher);

        Question question = new Question();
        question.setUsername("Jay");
        question.setQuestionContent("Java的主函数如何编写");

        // 触发数据变更
        course.produceQuestion(course, question);
    }
}
// 输出
Jay在Java设计模式精讲提交了一个问题
Alpha老师的Java设计模式精讲课程收到了一个Jay提交的问题Java的主函数如何编写
(2)应用
Guavacom.google.common.eventbus.EventBus

JDK
java.util.Observable/java.util.Observer
java.util.EventListener  
6.备忘录模式

保存一个对象的某个状态,以便在适当的时候恢复对象。为用户提供了一种可恢复机制。

实例
// 手记
public class Article {
    private String title;
    private String content;
    private String imgs;

    public Article(String title, String content, String imgs) {
        this.title = title;
        this.content = content;
        this.imgs = imgs;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getImgs() {
        return imgs;
    }

    public void setImgs(String imgs) {
        this.imgs = imgs;
    }

    public ArticleMemento saveToMemento() {
        return new ArticleMemento(title, content, imgs);
    }

    public void undoFromMemento(ArticleMemento memento) {
        this.content = memento.getContent();
        this.title = memento.getTitle();
        this.imgs = memento.getImgs();
    }

    @Override
    public String toString() {
        return "Article{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", imgs='" + imgs + '\'' +
                '}';
    }
}

// 手记备忘录
public class ArticleMemento {
    private String title;
    private String content;
    private String imgs;

    public ArticleMemento(String title, String content, String imgs) {
        this.title = title;
        this.content = content;
        this.imgs = imgs;
    }

    public String getTitle() {
        return title;
    }

    public String getContent() {
        return content;
    }

    public String getImgs() {
        return imgs;
    }

    @Override
    public String toString() {
        return "ArticleMemento{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", imgs='" + imgs + '\'' +
                '}';
    }
}

// 手记备忘录 管理器
public class ArticleMementoManager {
    private final Stack<ArticleMemento> articleMementoStack = new Stack<>();

    public void addMemento(ArticleMemento articleMemento) {
        articleMementoStack.push(articleMemento);
    }

    public ArticleMemento getArticleMemento() {
        // 拿出的总是最新的记录
        return articleMementoStack.pop();
    }

}

// 备忘录模式测试
public class Test {
    public static void main(String[] args) {
        ArticleMementoManager articleMementoManager = new ArticleMementoManager();

        Article article = new Article("如影随形的设计模式A", "手记内容A", "手记图片A");

        ArticleMemento articleMemento = article.saveToMemento();

        articleMementoManager.addMemento(articleMemento);

        System.out.println("标题:" + article.getTitle() + " 内容:" + article.getContent() + " 图片:" + article.getImgs());

        System.out.println("手记完整信息:" + article);

        System.out.println("修改手记 start");

        article.setTitle("如影随形的设计模式B");
        article.setContent("手记内容B");
        article.setImgs("手记图片B");

        System.out.println("修改手记 end");
        System.out.println("手记完整信息:" + article);

        articleMemento = article.saveToMemento();
        articleMementoManager.addMemento(articleMemento);

        article.setTitle("如影随形的设计模式C");
        article.setContent("手记内容C");
        article.setImgs("手记图片C");

        System.out.println("暂存回退start");

        System.out.println("回退出栈1次");
        articleMemento = articleMementoManager.getArticleMemento();
        article.undoFromMemento(articleMemento);

        System.out.println("回退出栈2次");
        articleMemento = articleMementoManager.getArticleMemento();
        article.undoFromMemento(articleMemento);

        System.out.println("暂存回退end");
        System.out.println("手记完整信息:" + article);
    }

}
// 输出
标题如影随形的设计模式A 内容手记内容A 图片手记图片A
手记完整信息Article{title='如影随形的设计模式A', content='手记内容A', imgs='手记图片A'}
修改手记 start
修改手记 end
手记完整信息Article{title='如影随形的设计模式B', content='手记内容B', imgs='手记图片B'}
暂存回退start
回退出栈1次
回退出栈2次
暂存回退end
手记完整信息Article{title='如影随形的设计模式A', content='手记内容A', imgs='手记图片A'}
7.命令模式

将”请求”封装成对象,以便使用不同的请求。命令模式解决了应用程序中对象的职责以及它们之间的通信方式。

(1)实例
// 课程视频
public class CourseVedio {
    private String name;

    public CourseVedio(String name) {
        this.name = name;
    }

    public void open() {
        System.out.println(name + "课程视频打开");
    }

    public void close() {
        System.out.println(name + "课程视频关闭");
    }
}

// 命令
public interface Command {
    void execute();
}

// 具体命令
public class OpenCourseVedioCommand implements Command {

    private CourseVedio courseVedio;

    public OpenCourseVedioCommand(CourseVedio courseVedio) {
        this.courseVedio = courseVedio;
    }

    @Override
    public void execute() {
        courseVedio.open();
    }
}

// 具体命令
public class CloseCourseVedioCommand implements Command {

    private CourseVedio courseVedio;

    public CloseCourseVedioCommand(CourseVedio courseVedio) {
        this.courseVedio = courseVedio;
    }

    @Override
    public void execute() {
        courseVedio.close();
    }
}

// 员工
public class Staff {
    private List<Command> commandList = new ArrayList<>();

    public void addCommand(Command command) {
        commandList.add(command);
    }

    public void executeCommands() {
        commandList.forEach(Command::execute);
        commandList.clear(); // 清空命令列表
    }
}

// 命令模式测试
public class Test {
    public static void main(String[] args) {

        CourseVedio courseVedio = new CourseVedio("Java设计模式精讲");
        OpenCourseVedioCommand openCourseVedioCommand = new OpenCourseVedioCommand(courseVedio);
        CloseCourseVedioCommand closeCourseVedioCommand = new CloseCourseVedioCommand(courseVedio);

        Staff staff = new Staff();
        // 添加命令
        staff.addCommand(openCourseVedioCommand);
        staff.addCommand(closeCourseVedioCommand);
        // 执行命令
        staff.executeCommands();

    }
}
// 输出
Java设计模式精讲课程视频打开
Java设计模式精讲课程视频关闭
(2)应用

java.lang.Runnable–不同的实现,不同的Task

8.中介者模式

定义一个 封装一组对象如何交互 的对象。通过使对象明确地相互引用来促进松散耦合,并允许独立地改变它们的交互。

(1)实例
// 学习群,中介者
public class StudyGroup {

    // 决定了User如何交互的行为
    public static void sendMessage(User user, String message) {
        System.out.println(new Date() + " [" + user.getName() + "]: " + message);
    }

}

// 用户
public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
		// 发送消息
    public void sendMessage(String message) {
        StudyGroup.sendMessage(this, message);
    }
}

// 中介者模式测试
public class Test {
    public static void main(String[] args) {
        User tom = new User("Tom");
        User lucy = new User("Lucy");

        tom.sendMessage("Hi Lucy! Let's learn design pattern!");
        lucy.sendMessage("OK!");
    }
}
// 输出
Tue Apr 02 22:04:40 CST 2019 [Tom]: Hi Lucy! Let's learn design pattern!
Tue Apr 02 22:04:40 CST 2019 [Lucy]: OK!
(2)应用

中介者 java.util.Timer,方法java.util.Timer.sched,被封装的对象:TimerTask。

9.责任链模式

为请求创建一个接受此次请求对象的链。

(1)实例
// 课程
public class Course {
    private String name;
    private String article;
    private String video;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getArticle() {
        return article;
    }

    public void setArticle(String article) {
        this.article = article;
    }

    public String getVideo() {
        return video;
    }

    public void setVideo(String video) {
        this.video = video;
    }

    @Override
    public String toString() {
        return "Course{" +
                "name='" + name + '\'' +
                ", article='" + article + '\'' +
                ", video='" + video + '\'' +
                '}';
    }
}

// 批准者
public abstract class Approver {
    protected Approver next;

    public void setNext(Approver next) {
        this.next = next;
    }

    /**
     * 发布课程
     * @param course
     */
    protected abstract void deploy(Course course);
}
// 手记检查
public class ArticleApprover extends Approver {
    @Override
    protected void deploy(Course course) {
        if (StringUtils.isNotEmpty(course.getArticle())) {
            System.out.println(course.getName() + "课程手记检查通过,批准");
            if (next != null) {
                next.deploy(course);
            }
        } else {
            System.out.println(course.getName() + "课程手记检查不通过,不批准,流程结束");
        }
    }
}
// 视频检查
public class VideoApprover extends Approver {
    @Override
    protected void deploy(Course course) {
        if (StringUtils.isNotEmpty(course.getVideo())) {
            System.out.println(course.getName() + "课程视频检查通过,批准");
            if (next != null) {
                next.deploy(course);
            }
        } else {
            System.out.println(course.getName() + "课程视频检查不通过,不批准,流程结束");
        }
    }
}

// 责任链模式测试
public class Test {
    public static void main(String[] args) {
        Approver articleApprover = new ArticleApprover();
        Approver videoApprover = new VideoApprover();

        Course course = new Course();
        course.setName("Java设计模式精讲");
        course.setArticle("Java设计模式精讲手记");
        course.setVideo("Java设计模式精讲视频");

        articleApprover.setNext(videoApprover);

        articleApprover.deploy(course);
    }
}
// 输出
Java设计模式精讲课程手记检查通过批准
Java设计模式精讲课程视频检查通过批准
(2)应用
javax.servlet.Filter

javax.servlet.FilterChain
10.访问者模式

封装作用于某种数据结构(如List/Set/Map等)中的各种元素的操作。可以在不改变各元素的类的前提下,定义作用于这些元素的操作。

(1)实例
// 课程
public abstract class Course {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    /**
     * 针对不同角色的访问者,设置不同的访问权限
     * @param visitor 访问者
     */
    public abstract void accept(IVisitor visitor);
}
// 付费课程
public class CodingCourse extends Course {
    private int price;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public void accept(IVisitor visitor) {
        // 针对不同角色的访问者,设置不同的访问权限
        visitor.visit(this);
    }
}
// 免费课程
public class FreeCourse extends Course {
    @Override
    public void accept(IVisitor visitor) {
        // 针对不同角色的访问者,设置不同的访问权限
        visitor.visit(this);
    }
}

// 访问者  不同的visitor,对相同的数据,产生不同的行为
public interface IVisitor {
    void visit(FreeCourse freeCourse);

    void visit(CodingCourse codingCourse);
}
// 访问者实现
public class Visitor implements IVisitor {
    // 不同的visitor,对相同的数据,产生不同的行为
    @Override
    public void visit(FreeCourse freeCourse) {
        System.out.println("免费课程:" + freeCourse.getName());
    }

    @Override
    public void visit(CodingCourse codingCourse) {
        System.out.println("付费课程:" + codingCourse.getName() + ", 价格:" + codingCourse.getPrice());
    }
}

// 访问者模式测试
public class Test {
    public static void main(String[] args) {
        // 数据准备
        List<Course> courseList = new ArrayList<>();

        FreeCourse freeCourse = new FreeCourse();
        freeCourse.setName("Spring实战");

        CodingCourse codingCourse = new CodingCourse();
        codingCourse.setName("Java设计模式");
        codingCourse.setPrice(199);

        courseList.add(freeCourse);
        courseList.add(codingCourse);

        // 数据操作
        IVisitor visitor = new Visitor();
        for (Course course : courseList) {
            course.accept(visitor);
        }
    }
}
// 输出
免费课程Spring实战
付费课程Java设计模式, 价格199
(2)应用
java.nio.file.FileVisitor

org.springframework.beans.factory.config.BeanDefinitionVisitor
11.状态模式

允许一个对象在其内部状态发生改变时,改变它的行为。不同状态,行为不同,且状态可相互转换。

实例
// 上下文,行为依赖于内部状态
public class CourseVideoContext {
    private CourseVideoState courseVideoState;

    public CourseVideoState getCourseVideoState() {
        return courseVideoState;
    }

    public void setCourseVideoState(CourseVideoState courseVideoState) {
        this.courseVideoState = courseVideoState;
        // 重要
        this.courseVideoState.setCourseVideoContext(this);
    }

    public static final PlayState PLAY_STATE = new PlayState();
    public static final SpeedState SPEED_STATE = new SpeedState();
    public static final PauseState PAUSE_STATE = new PauseState();
    public static final StopState STOP_STATE = new StopState();

    // 行为根据状态CourseVideoState的变化而变化
    public void play() {
        this.courseVideoState.play();
    }

    public void speed() {
        this.courseVideoState.speed();
    }

    public void stop() {
        this.courseVideoState.stop();
    }

    public void pause() {
        this.courseVideoState.pause();
    }
}

// 状态
public abstract class CourseVideoState {
    protected CourseVideoContext courseVideoContext;

    public void setCourseVideoContext(CourseVideoContext courseVideoContext) {
        this.courseVideoContext = courseVideoContext;
    }

    public abstract void play();
    public abstract void speed();
    public abstract void pause();
    public abstract void stop();
}
// 播放状态
public class PlayState extends CourseVideoState {
    @Override
    public void play() {
        System.out.println("正常播放课程视频状态");
    }

    @Override
    public void speed() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
    }

    @Override
    public void pause() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}
// 快进状态
public class SpeedState extends CourseVideoState {
    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        System.out.println("快进播放课程视频状态");
    }

    @Override
    public void pause() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}
// 暂停状态
public class PauseState extends CourseVideoState {
    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
    }

    @Override
    public void pause() {
        System.out.println("暂停播放课程视频状态");
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}
// 停止状态
public class StopState extends CourseVideoState {
    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        System.out.println("ERROR! 停止状态无法快进");
    }

    @Override
    public void pause() {
        System.out.println("ERROR! 停止状态无法暂停");
    }

    @Override
    public void stop() {
        System.out.println("停止播放课程视频状态");
    }
}

// 状态模式测试
public class Test {
    public static void main(String[] args) {
        CourseVideoContext courseVideoContext = new CourseVideoContext();
        courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);

        System.out.println("当前状态: " + courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.pause();

        System.out.println("当前状态: " + courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.speed();

        System.out.println("当前状态: " + courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.stop();

        System.out.println("当前状态: " + courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.speed();
    }
}
// 输出
当前状态: PlayState
当前状态: PauseState
当前状态: SpeedState
当前状态: StopState
ERROR! 停止状态无法快进

五、设计模式总结

1.创建型

重点:工厂方法模式、抽象工厂模式、建造者模式、单例模式;

一般:原型模式。

2.结构型

重点:适配器模式、装饰者模式、代理模式、外观模式、桥接模式、享元模式;

一般:组合模式。

3.行为型

重点:策略模式、责任链模式、模板方法模式、状态模式、观察者模式、命令模式;

一般:备忘录模式、迭代器模式、中介者模式、访问者模式、解释器模式。

参考