文章目录

  • 前言
  • 设计模式六大原则
  • 1.单一原则
  • (1) 概念
  • (2) 优点
  • 2.开闭原则
  • (1) 概念
  • 3.里氏替换原则
  • (1) 概念
  • 4.依赖倒置原则
  • (1) 概念
  • (2) 作用
  • 5.接口隔离原则
  • (1) 概念
  • 6.迪米特原则
  • (1) 概念
  • 一、单例模式
  • 1.概念
  • 2.单例模式应用
  • (1) 懒汉式 基础版
  • (2) 懒汉式 双重校验锁版
  • (3) 饿汉式 单例模式
  • (4) 登记式 单例模式
  • 二、策略模式
  • 1.概念
  • 2.策略模式应用(导航不同工具耗时为例)
  • (1) 创建策略接口
  • (2) 创建不同方式导航策略
  • (3) 创建策略上下文
  • (4) 业务测试类
  • 三、工厂方法模式
  • 1.概念
  • 2.工厂方法模式应用(轮胎生产商举例)
  • (1) 需求示例:
  • (2) 创建轮胎工厂接口以及轮胎生产接口
  • (3) 创建具体轮胎生产工厂类以及具体轮胎生产类
  • (4) 客户端需求测试
  • 四、模板方法模式
  • 1. 概念
  • 2. 模板方法模式(穷富男孩约会流程为例)
  • (1) 创建约会流程抽象类
  • (2) 创建 穷男孩 富男孩各自约会类继承约会抽象类
  • (3) 创建测试类 测试各自约会流程
  • 五、抽象工厂模式
  • 1.概念
  • 2.抽象工厂模式
  • (1) 创建抽象酒类 葡萄酒类 果酒类
  • (2) 创建两种不同品牌生产商继承各类抽象酒
  • (3) 创建工厂接口 创建 生产不同酒类的工厂的方法
  • (4) 不同品牌工厂继承酒类生产工厂
  • (5) 测试类进行测试
  • 六、代理模式
  • 1.概念
  • 2.代理模式应用
  • (1) 静态代理模式(有缺点)---出租房为例
  • ① 创建出租接口
  • ② 创建房东实例
  • ③ 创建中介代理房东出租房子
  • ④ 租客找中介租房子
  • (3) 动态代理模式(解决静态代理模式缺点)
  • ① 改造静态代理模式例子 摒弃中介代理类创建动态代理类
  • ② 租客租房子
  • 七、适配器模式
  • 1.概念
  • 2.适配器模式应用
  • (1) 类适配器模式
  • (2) 对象适配器模式
  • 八、装饰器模式
  • 1.概念
  • 2.装饰器模式应用
  • 九、观察者模式(订阅-分发模式)
  • 1.概念
  • 2.观察者模式应用(以组长给组员发工资为例)
  • (1) 创建抽象主题对象 和 抽象观察者
  • (2) 创建具体主题对象 和 具体观察者
  • (3) 测试类测试分发
  • 十、外观模式
  • 1.概念
  • 2.外观模式应用
  • 十一、状态模式
  • 1.概念
  • 2.状态模式应用
  • 十二、责任链模式
  • 1.概念
  • 2.责任链模式应用
  • 十三、享元模式
  • 1.概念
  • 2.优缺点
  • (1) 优点
  • (2) 缺点
  • 3.享元模式应用(共享单车为例)
  • (1) 创建共享单车抽象类
  • (2) 创建具体单车类
  • (3) 创建单车工厂类
  • (4) 测试
  • 十四、命令模式
  • 1.概念
  • 2.参考文章
  • 十五、生成器模式
  • 1.概念
  • 2.生成器模式应用
  • 十六、原型模式
  • 十七、备忘录模式
  • 1.概念
  • 2. 备忘录模式应用
  • 十八、迭代器模式
  • 十九、组合模式
  • 1.概念
  • 2.组合模式应用
  • 二十、桥接模式
  • 1.概念
  • 2.桥接模式应用
  • 二十一、中介者模式
  • 1.概念
  • 2.中介者模式应用
  • 二十二、访问者模式
  • 1.概念



前言

Java的 23种设计模式

创建型模式,共五种(1-5):工厂方法模式、抽象工厂模式、单例模式、生成器模式、原型模式。

结构型模式,共七种(6-12):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种(13-23):策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

其实还有两类:并发型模式和线程池模式


设计模式六大原则

1.单一原则

(1) 概念

一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

(2) 优点

  • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
  • 提高类的可读性,提高系统的可维护性;
  • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响

2.开闭原则

(1) 概念

一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展

3.里氏替换原则

(1) 概念

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

4.依赖倒置原则

(1) 概念

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象,其核心思想是:要面向接口编程,不要面向实现编程。

(2) 作用

  • 依赖倒置原则可以降低类间的耦合性。
  • 依赖倒置原则可以提高系统的稳定性。
  • 依赖倒置原则可以减少并行开发引起的风险。
  • 依赖倒置原则可以提高代码的可读性和可维护性。

5.接口隔离原则

(1) 概念

使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

6.迪米特原则

(1) 概念

一个软件实体应当尽可能少地与其他实体发生相互作用。

一、单例模式

1.概念

java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。

单例模式有以下特点:

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

2.单例模式应用

(1) 懒汉式 基础版

// 懒汉式单例类 先声明 在第一次调用的时候实例化自己
public class Idler {
	// 构造方法
    private Idler () {}
    private static Idler idler ;
    
    // 静态工厂方法 
    public static Idler getIdler () {
         if (idler == null) {  
             idler= new idler();
         }  
        return idler;
    }
}

(2) 懒汉式 双重校验锁版

防止多线程创建单例模式时 造成多次被实例化

// 懒汉式单例类 先声明 在第一次调用的时候实例化自己
public class Idler {
	// 构造方法
    private Idler () {}
    private static Idler idler ;
    
    // 静态工厂方法 
    public static Idler getIdler () {
         if (idler == null) {  
           synchronized (Idler.class) {
             if (idler == null) {
               idler= new idler();
             }
           }
         }  
        return idler;
    }
}

(3) 饿汉式 单例模式

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

// 饿汉单例类 初始化时实例化自己
public class Idler {
	// 构造方法
    private Idler () {}
    private static Idler idler = new idler();
    
    // 静态工厂方法 
    public static Idler getIdler () {
        return idler;
    }
}

(4) 登记式 单例模式

package 创建型_单例模式_登记式;
 
import java.util.HashMap;
import java.util.Map;
 
/**
 * 登记式单例实际上维护的是一组单例类的实例,将这些实例存储到一个Map(登记簿)
 * 中,对于已经登记过的单例,则从工厂直接返回,对于没有登记的,则先登记,而后
 * 返回
 * @author pp
 *
 */
public class Example{
    /**
     * 登记簿,用来存放所有登记的实例
     */
    private static Map<String, Example> map = new HashMap<String, Example>();
    //在类加载时添加一个实例到登记簿
    static {
        Example example= new Example();
        map.put(example.getClass().getName(), example);//运用了反射
    }
    /**
     * 受保护的默认构造方法
     */
    protected Example() {
        
    }
    /**
     * 静态工厂方法,返回指定登记对象的唯一实例
     * 对于已经登记的直接取出返回,对于还未登记的先登记,然后取出返回
     *
     */
    public static Example getExample(String name){
        if(name == null){
            name="firstExample";
        }
        if(map.get(name) == null){
            try {
                map.put(name, (Example) Class.forName(name).newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return map.get(name);
    }
   
}

二、策略模式

1.概念

其思想是针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而使它们可以相互替换。策略模式可以让算法在不影响客户端的情况下发生变化

2.策略模式应用(导航不同工具耗时为例)

(1) 创建策略接口

/**
 * 导航接口
 * 导航策略接口
 */
public interface Navigation {
    // 耗时方法
    void elapsedTime();
}

(2) 创建不同方式导航策略

/**
 * 步行导航用时方法
 */
public class Walk implements Navigation {
    @Override
    // 步行导航消耗时间方法
    public void elapsedTime() {
        System.out.println("步行到达目的地需20分钟");
    }
}
/**
 * 骑车导航用时方法
 */
public class Bike implements Navigation {
    // 骑车导航耗时方法
    @Override
    public void elapsedTime() {
        System.out.println("骑车到达目的地需10分钟");
    }
}
public class Car implements Navigation {
    // 骑车导航耗时方法
    @Override
    public void elapsedTime() {
        System.out.println("开车到达目的地需2分钟");
    }
}

(3) 创建策略上下文

/**
 * 策略上下文
 */
public class NavigationContext {
    // 声明接口对象
    private Navigation navigation;

    // 使用构造器注入具体的策略类
    public NavigationContext(Navigation navigation) {
        this.navigation = navigation;
    }

    // 也可以通过set方法注入具体策略
    public void setNavigation(Navigation navigation) {
        this.navigation = navigation;
    }

    // 调用策略实现的方法
    public void elapsedTime() {
        navigation.elapsedTime();
    }
}

(4) 业务测试类

/**
 * 业务测试类
 */
public class TestNavigation {
    public static void main(String[] args) {
        // 传入步行导航策略
        Walk walk = new Walk();
        NavigationContext navigationContext = new NavigationContext(walk);
        navigationContext.elapsedTime();

        // 传入骑车导航策略
        navigationContext.setNavigation(new Bike());
        navigationContext.elapsedTime();

        // 传入开车导航策略
        navigationContext.setNavigation(new Car());
        navigationContext.elapsedTime();

    }
}

三、工厂方法模式

1.概念

工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。

2.工厂方法模式应用(轮胎生产商举例)

(1) 需求示例:

java设计模式在工作中真的有应用吗 java设计模式及应用案例_System

(2) 创建轮胎工厂接口以及轮胎生产接口

/**
 * 轮胎接口
 */
public interface Tyre {
    // 生产轮胎方法
    void produceTyre();
}
/**
 * 轮胎工厂
 */
public interface TyreFactory {
    // 轮胎工厂方法
    Tyre produceTyreFactory();
}

(3) 创建具体轮胎生产工厂类以及具体轮胎生产类

/**
 * 玲珑轮胎工厂
 */
public class LingLongFactory implements TyreFactory {
    // 生产玲珑轮胎
    @Override
    public Tyre produceTyreFactory() {
        return new LingLongTyre();
    }
}
public class LingLongTyre implements Tyre{
    // 玲珑轮胎生产中
    @Override
    public void produceTyre() {
        System.out.println("玲珑轮胎生产中!");
    }
}
/**
 * 米其林轮胎生产工厂
 */
public class MichelinFactory implements TyreFactory {
    // 生产米其林轮胎
    @Override
    public Tyre produceTyreFactory() {
        return new MichelinTyre();
    }
}
public class MichelinTyre implements Tyre {
    // 米其林轮胎生产中
    @Override
    public void produceTyre() {
        System.out.println("米其林轮胎生产中!");
    }
}

(4) 客户端需求测试

/**
 * 轮胎定制客户端
 */
public class TestTyre {
    public static void main(String[] args) {
        // 声明需要生产轮胎
        Tyre tyre;

        // 生产米其林轮胎
        // 创建米其林生产轮胎的工厂
        TyreFactory tyreFactory = new MichelinFactory();
        tyre = tyreFactory.produceTyreFactory();
        tyre.produceTyre();

        // 生产玲珑轮胎
        // 创建玲珑轮胎工厂
        tyreFactory = new LingLongFactory();
        tyre = tyreFactory.produceTyreFactory();
        tyre.produceTyre();

    }
}

四、模板方法模式

1. 概念

定义一个操作中的算法的框架,将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

2. 模板方法模式(穷富男孩约会流程为例)

(1) 创建约会流程抽象类

public abstract class Date {
    // 洗澡 洗香香方法
    protected void bath() {
        System.out.println("给自己洗澡");
    }

    // 筹备约会资金
    protected void money() {
        System.out.println("给自己搞点钱");
    }

    // 定好约会地点
    protected void site() {
        System.out.println("定好位置");
    }

    // 约会总流程方法
    public final void dateTemplate() {
        System.out.println("打电话约女朋友");
        bath();
        money();
        site();
        System.out.println("约会结束,爽歪歪");
    }
}

(2) 创建 穷男孩 富男孩各自约会类继承约会抽象类

/**
 * 穷男孩的约会方式流程
 */
public class PoorBoy extends Date{
    // 重写搞钱方法
    @Override
    public void money() {
        System.out.println("找好兄弟东拼西凑");
    }
    // 重写约会地点方法
    @Override
    public void site() {
        System.out.println("带女朋友吃烧烤");
    }
}
/**
 * 富男孩的约会流程
 */
public class RichBoy extends Date {
    // 重写搞钱方法
    @Override
    public void money() {
        System.out.println("打电话给老爹,让其打钱");
    }

    // 重写约会地点方法
    @Override
    public void site() {
        System.out.println("去高档餐厅吃西餐");
    }
}

(3) 创建测试类 测试各自约会流程

public class TestDate {
    public static void main(String[] args) {
        // 穷男孩约会
        Date date = new PoorBoy();
        date.dateTemplate();

        // 富男孩约会
        date = new RichBoy();
        date.dateTemplate();
    }
}

五、抽象工厂模式

1.概念

抽象工厂模式 是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。

2.抽象工厂模式

(1) 创建抽象酒类 葡萄酒类 果酒类

/**
 * 酒的抽象类
 */
public abstract class Liquor {
    protected abstract void sell();
}
/**
 * 葡萄酒抽象类
 */
public abstract class Wine extends Liquor {
    @Override
    protected abstract void sell();
}
/**
 * 果酒抽象类
 */
public abstract class FruitWine extends Liquor{
    @Override
    protected abstract void sell();
}

(2) 创建两种不同品牌生产商继承各类抽象酒

/**
 * 张裕葡萄酒具体实现类
 */
public class ZhangYuWine extends Wine {
    @Override
    protected void sell() {
        System.out.println("张裕葡萄酒你值得拥有!");
    }
}
/**
 * Petrus葡萄酒具体实现类
 */
public class PetrusWine extends Wine {
    @Override
    protected void sell() {
        System.out.println("Petrus葡萄酒真不错!");
    }
}
/**
 * 张裕果酒实现类
 */
public class ZhangYuFruitWine extends FruitWine{
    @Override
    protected void sell() {
        System.out.println("张裕果酒你值得拥有!");
    }
}
/**
 * Petrus果酒实现类
 */
public class PetrusFruitWine extends FruitWine {
    @Override
    protected void sell() {
        System.out.println("Petrus果酒真不错!");
    }
}

(3) 创建工厂接口 创建 生产不同酒类的工厂的方法

/**
 * 工厂接口
 */
public interface Factory {
    // 葡萄酒类生产工厂方法
    Liquor productWine();
    // 果酒类生产工厂方法
    Liquor productFruitWine();
}

(4) 不同品牌工厂继承酒类生产工厂

/**
 * 张裕酒类生产工厂
 */
public class ZhangYuFactory implements Factory {
    // 葡萄酒
    @Override
    public Liquor productWine() {
        return new ZhangYuWine();
    }

    // 果酒
    @Override
    public Liquor productFruitWine() {
        return new ZhangYuFruitWine();
    }
}
/**
 * Petrus酒类生产工厂
 */
public class PetrusFactory implements Factory{
    // 葡萄酒
    @Override
    public Liquor productWine() {
        return new PetrusWine();
    }

    // 果酒
    @Override
    public Liquor productFruitWine() {
        return new PetrusFruitWine();
    }
}

(5) 测试类进行测试

public class TestLiquor {
    public static void main(String[] args) {
        // 定制张裕酒类
        Factory zhangYuFactory = new ZhangYuFactory();
        // 葡萄酒
        zhangYuFactory.productWine().sell();
        // 果酒
        zhangYuFactory.productFruitWine().sell();
        // 定制Petrus酒类
        Factory petrusFactory = new PetrusFactory();
        // 葡萄酒
        petrusFactory.productWine().sell();
        // 果酒
        petrusFactory.productFruitWine().sell();
    }
}

六、代理模式

1.概念

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

2.代理模式应用

(1) 静态代理模式(有缺点)—出租房为例

优点:
1.代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
2.代理对象可以扩展目标对象的功能;
3.代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度

缺点:
1.在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
2.增加了系统的复杂度;

① 创建出租接口
/**
 * 出租房子接口
 */
public interface RentInterface {
    // 出租房子方法
    void rent();
}
② 创建房东实例
/**
 * 房东类
 */
public class Landlord implements RentInterface{
    @Override
    public void rent() {
        System.out.println("我是房东我要出售一套房子价格200大洋");
    }
}
③ 创建中介代理房东出租房子
/**
 * 中介代理类
 */
public class Proxy implements RentInterface{
    private Landlord landlord;

    void price() {
        System.out.println("收个20大洋中介费");
    }

    @Override
    public void rent() {
        price();
        landlord = new Landlord();
        landlord.rent();
    }
}
④ 租客找中介租房子
/**
 * 租客
 */
public class Tenant {
    public static void main(String[] args) {
        // 找到中介租房子
        Proxy proxy = new Proxy();
        proxy.rent();

    }

}

java设计模式在工作中真的有应用吗 java设计模式及应用案例_class_02

(3) 动态代理模式(解决静态代理模式缺点)

① 改造静态代理模式例子 摒弃中介代理类创建动态代理类
/**
 * 动态代理类
 */
public class DynamicProxy implements InvocationHandler {
    // 声明需要代理的类
    private Object proxy;

    // 提供set
    public void setProxy(Object proxy) {
        this.proxy = proxy;
    }

    // 提供get  方法
    public Object getProxy() {
        // 三个参数固定写死 一个是获取getClassLoader 第二个获取代理类接口 第三个是动态代理类本身
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), proxy.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object object, Method method, Object[] args) throws Throwable {
        message(method.getName());
        Object result = method.invoke(proxy, args);
        return result;
    }

    // 打印代理类执行了真实对象什么方法
    private void message(String msg) {
        System.out.println(msg);
    }
}
② 租客租房子
/**
 * 租客
 */
public class Tenant {
    public static void main(String[] args) {
        // 找到中介租房子
//        Proxy proxy = new Proxy();
//        proxy.rent();

        // 创建房东对象
        Landlord landlord = new Landlord();
        // 创建动态代理对象
        DynamicProxy dynamicProxy = new DynamicProxy();
        dynamicProxy.setProxy(landlord);

        // 拿到代理对象
        RentInterface rentInterface = (RentInterface) dynamicProxy.getProxy();

        // 调用代理对象
        rentInterface.rent();
    }
}

java设计模式在工作中真的有应用吗 java设计模式及应用案例_class_03

七、适配器模式

1.概念

将某个类的接口转换为接口客户所需的类型。换句话说,适配器模式解决的问题是,使得原本由于接口不兼容而不能一起工作、不能统一管理的那些类可以在一起工作、可以进行统一管理。

2.适配器模式应用

(1) 类适配器模式

/**
 * 原有业务类
 * 快递员只发送顺丰快递
 */
public class Expressage {
    public void send(){
        System.out.println("快递员发顺丰快递!");
    }
}


/**
 * 业务接口
 */
public interface BusinessInterface {
    // 新加业务
    void newSend();
}



/**
 * 新业务实现类
 */
public class BusinessNewSend implements BusinessInterface{
    // 实现新业务
    @Override
    public void newSend() {
        System.out.println("新业务发送其他快递!");
    }
}


/**
 * 适配器类
 * 实现旧业务
 */
public class BusinessAdapter extends Expressage implements BusinessInterface {
    // 调用旧业务
    @Override
    public void newSend() {
        super.send();
    }

}



public class Test {
    public static void main(String[] args) {
        // 旧业务
        BusinessInterface businessInterface = new BusinessAdapter();
        businessInterface.newSend();
        // 新业务
        BusinessInterface businessInterface1 = new BusinessNewSend();
        businessInterface1.newSend();

    }
}

(2) 对象适配器模式

/**
 * 原有业务类
 * 快递员只发送顺丰快递
 */
public class Expressage {
    public void send(){
        System.out.println("快递员发顺丰快递!");
    }
}


/**
 * 业务接口
 */
public interface BusinessInterface {
    // 新加业务
    void newSend();
}


/**
 * 适配器类
 */
public class BusinessAdapter implements BusinessInterface {
    private Expressage expressage;

    public BusinessAdapter(Expressage expressage){
        this.expressage = expressage;
    }

    // 实现新业务
    @Override
    public void newSend() {
        expressage.send();
        System.out.println("新业务发送其他快递!");
    }
}

public class Test {
    public static void main(String[] args) {

        Expressage expressage = new Expressage();
        BusinessInterface businessInterface = new BusinessAdapter(expressage);
        // 旧业务
        expressage.send();
        // 新业务
        businessInterface.newSend();

    }
}

八、装饰器模式

注: 装饰器与适配器的区别是 装饰器是实现旧业务接口 为旧业务增加新方法 适配器是实现新业务在新业务中调用旧业务

1.概念

是指在不改变原有对象的基础之上,将功能附加到对象上.提供了比继承更灵活的替代方法 属于结构型模式.

2.装饰器模式应用

/**
 * 机器人接口
 */
public interface Robot {
	// 会唱歌
    void sing();
}



/**
 * 第一代机器人
 */
public class FirstRobot implements Robot{
    @Override
    public void sing() {
        System.out.println("我会唱歌,a b c d e f g~");
    }
}



/**
 * 装饰类
 * 装饰机器人
 */
public class DecoratorRobot implements Robot{
    private Robot robot;

    public DecoratorRobot(Robot robot) {
        this.robot = robot;
    }

    // 调用旧方法
    @Override
    public void sing() {
        robot.sing();
    }

    // 新方法
    public void jump() {
        System.out.println("我还会跳高高!");
    }
}




public class Test {
    public static void main(String[] args) {
        DecoratorRobot decoratorRobot = new DecoratorRobot(new FirstRobot());
        decoratorRobot.sing();
        decoratorRobot.jump();
    }
}

九、观察者模式(订阅-分发模式)

1.概念

它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

2.观察者模式应用(以组长给组员发工资为例)

(1) 创建抽象主题对象 和 抽象观察者

/**
 * 领导接口
 * 抽象主题
 */
public interface Leader {
    // 添加员工入组方法
    void addPerson(GroupObserver groupObserver);
    // 给组员发工资
    void grantMoney();
}

/**
 * 组员接口
 * 抽象观察者
 */
public interface GroupObserver {
    // 跟组长要工资
    void getMoney();
}

(2) 创建具体主题对象 和 具体观察者

/**
 * A组 组长类
 */
public class GroupLeaderA implements Leader {
    private List<GroupObserver> observerList = new LinkedList<>();

    // 添加组员
    @Override
    public void addPerson(GroupObserver groupObserver) {
        observerList.add(groupObserver);
    }

    // 通知发工资
    @Override
    public void grantMoney() {
        observerList.forEach(GroupObserver::getMoney);
    }
}

// 组员张三
public class ZhangSan implements GroupObserver{
    @Override
    public void getMoney() {
        System.out.println("请给我张三发本月工资!");
    }
}

// 组员李四
public class LiSi implements GroupObserver{
    @Override
    public void getMoney() {
        System.out.println("请给我李四发这个月工资!");
    }
}

(3) 测试类测试分发

public class Test {
    public static void main(String[] args) {
        // 创建A组 组长
        Leader leader = new GroupLeaderA();
        // 添加组员
        leader.addPerson(new ZhangSan());
        leader.addPerson(new LiSi());
        // 发放工资
        leader.grantMoney();
    }
}

十、外观模式

1.概念

外观模式就是提供一个统一的接口,用来访问子系统的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。,外观模式也称门面模式,是一种对象结构型设计模式。

2.外观模式应用

/**
 * 认证类
 * 专门认证
 */
class Authentication{
    public void getAuthentication(){
        System.out.println("证明我是我!");
    }
}
/**
 * 盖章类
 * 专门盖章
 */
class Seal {
    public void getSeal() {
        System.out.println("证明完了盖章走人!");
    }
}

/**
 * 制证类
 * 制作证件
 */
class Accreditation {
    public void getAccreditation() {
        System.out.println("制作证件,发给办证人");
    }
}

/**
 * 服务类
 * 专门服务
 */
class ServiceImpl {
    // 认证类
    private Authentication authentication = new Authentication();
    // 盖章类
    private Seal seal = new Seal();
    // 制证类
    private Accreditation accreditation = new Accreditation();

    // 服务方法
    public void getServiceImpl() {
        authentication.getAuthentication();
        seal.getSeal();
        accreditation.getAccreditation();
    }
}

// 客户制证类
class Controller{
    public static void main(String[] args) {
        ServiceImpl service = new ServiceImpl();
        service.getServiceImpl();
    }
}

十一、状态模式

1.概念

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象( Objects for States),状态模式是对象行为型模式

2.状态模式应用

/**
 * 状态接口
 */
public interface EmotionStatus {
    // 情绪方法
    void emotion();
}




/**
 * 实现状态接口 生气类
 */
public class AngryEmotion implements EmotionStatus {
    // 生气情绪
    @Override
    public void emotion() {
        System.out.println("非常生气!逐渐失控!");
    }
}




/**
 * 开心类 实现状态接口
 */
public class HappyStatus implements EmotionStatus {
    // 开心方法
    @Override
    public void emotion() {
        System.out.println("很开心!跟你一起玩!");
    }
}






/**
 * 实现状态接口 伤心状态类
 */
public class SadEmotion implements EmotionStatus {
    // 伤心情绪方法
    @Override
    public void emotion() {
        System.out.println("想哭!嚎啕大哭!");
    }
}



/**
 * 张三类
 */
public class ZhangSan {
    // 状态接口声明
    private EmotionStatus emotionStatus;
    // 挨打的次数
    private int playNum = 0;
    // 构造方法
    public ZhangSan(EmotionStatus emotionStatus){
        this.emotionStatus = emotionStatus;
    }
    // get方法  获取当前实例对象情绪
    public void getEmotion(){
        emotionStatus.emotion();
    }
    // 张三挨打方法 因为挨打次数不同会导致情绪又不同的变化
    public void play(){
        playNum ++;
        if(playNum == 1){
            emotionStatus = new AngryEmotion();
        }
        if(playNum == 2){
            emotionStatus = new SadEmotion();
        }
        emotionStatus.emotion();
    }
}

十二、责任链模式

1.概念

将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象处理。

2.责任链模式应用

/**
 * 领导抽象类 每一个具体领导实现类都应继承该类
 */
abstract class Handler {
    // 私有下一级领导
    protected Handler nextHandler;

    // 设置下一级领导
    public void setNextHandler(Handler nextHandler){
        this.nextHandler = nextHandler;
    }

    // 审批方法
    abstract void approve(int info);
}



/**
 * 组长领导类
 */
public class GroupLeader extends Handler {
    // 组长审批方法
    @Override
    void approve(int info) {
        if (info < 10) {
            System.out.println("组长审批通过!");
            return;
        }
        nextHandler.approve(info);
    }
}




/**
 * 老板领导类
 */
public class BossHandler extends Handler {
    // 老板审批方法
    @Override
    void approve(int info) {
        System.out.println("老板审批通过!");
    }
}




/**
 * 组员测试类
 */
public class ZhangSan {
    public static void main(String[] args) {
        // 创建组长领导类
        Handler handlerGroup = new GroupLeader();
        // 创建老板领导类
        Handler handlerBoss = new BossHandler();
        // 为组长领导设置下一级领导
        handlerGroup.setNextHandler(handlerBoss);
        // 请假理由
        handlerGroup.approve(9);
        handlerGroup.approve(11);
    }
}

十三、享元模式

1.概念

主要用于减少创建对象的数量,以减少内存占用和提高性能。

2.优缺点

(1) 优点

大大减少对象的创建,降低系统的内存,使效率提高。

(2) 缺点

提高了系统的复杂度,需要分离出外部状态【非享元角色】和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

3.享元模式应用(共享单车为例)

(1) 创建共享单车抽象类

/**
 * 共享单车抽象类
 */
public abstract class BikeSharing {
    // 共享单车当前状态 0为未被使用 1为被使用
    protected Integer status = 0;

    // 共享单车使用方法 改变内部状态 0->1
    abstract void use(String user);

    // 共享单车还车方法 改变内部状态 1->0
    abstract void back();

    public void getStatus() {
        System.out.println("当前单车使用状态:"+ (this.status == 1 ? "使用中" :  "未使用"));
    }
}

(2) 创建具体单车类

public class HaLuoBike extends BikeSharing {
    private String bikeId;

    // 构造方法
    public HaLuoBike(String bikeId) {
        this.bikeId = bikeId;
    }

    // 改变使用状态
    @Override
    void use(String user) {
        status = 1;
        System.out.println("单车编号" + this.bikeId + "正在被用户" + user + "使用!");
    }

    // 还车方法
    @Override
    void back() {
        status = 0;
        System.out.println("还车成功!");
    }
}

(3) 创建单车工厂类

/**
 * 共享单车创造工厂
 */
public class FlyweightFactory {
    // 创建工厂单例
    private static FlyweightFactory flyweightFactory = new FlyweightFactory();

    // 创建共享单车集合
    private Map<String, BikeSharing> bikeMap = new ConcurrentHashMap<>();

    // 工厂创建单车数量控制属性
    private Integer bikeSum = 5;

    // 构造方法 创建单车
    private FlyweightFactory() {
        for (int i = 0; i < this.bikeSum; i++) {
            this.bikeMap.put(String.valueOf(i+1), new HaLuoBike(String.valueOf(i+1)));
        }
    }

    // 工厂get方法
    public static FlyweightFactory getFlyweightFactory() {
        return flyweightFactory;
    }

    // 返回共享单车对象
    public BikeSharing getBike() {
        for (int i = 0; i < this.bikeMap.size(); i++) {
            if (this.bikeMap.get(String.valueOf(i+1)).status == 0) {
                return this.bikeMap.get(String.valueOf(i+1));
            }
        }
        return null;
    }

}

(4) 测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class Test {
    @org.junit.Test
    public static void main(String[] args) {
        BikeSharing bikeSharing = FlyweightFactory.getFlyweightFactory().getBike();
        bikeSharing.use("张三");
        bikeSharing.getStatus();

        BikeSharing bikeSharing1 = FlyweightFactory.getFlyweightFactory().getBike();
        bikeSharing1.use("李四");

        BikeSharing bikeSharing2 = FlyweightFactory.getFlyweightFactory().getBike();
        bikeSharing2.use("王五");

        BikeSharing bikeSharing3 = FlyweightFactory.getFlyweightFactory().getBike();
        bikeSharing3.use("赵六");

        BikeSharing bikeSharing4 = FlyweightFactory.getFlyweightFactory().getBike();
        bikeSharing4.use("田七");

        BikeSharing bikeSharing5 = FlyweightFactory.getFlyweightFactory().getBike();
        if (bikeSharing5 == null) {
            System.out.println("当前没有车可以使用!");
        }

        // 张三还车
        bikeSharing.back();
        BikeSharing bikeSharing6 = FlyweightFactory.getFlyweightFactory().getBike();
        bikeSharing6.use("勾八");

    }
}

十四、命令模式

1.概念

将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或者对请求做日志记录,以及可以支持撤销的操作。

2.参考文章


十五、生成器模式

1.概念

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

2.生成器模式应用

IDEA下载插件

java设计模式在工作中真的有应用吗 java设计模式及应用案例_class_04


在需要生成的类中使用快捷键: Alt + Insert

java设计模式在工作中真的有应用吗 java设计模式及应用案例_java_05


也可以直接在类中加上lombok的注解@Builder实现同样效果。

十六、原型模式

概念:

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

十七、备忘录模式

1.概念

在不破坏封装性的前提下捕获一个对象内部的状态,并在对象之外保存这个状态,以便对象以后恢复到这一状态。

2. 备忘录模式应用

// 备忘录接口
public interface Memo {
}


// 备忘录类
public class BackUp implements Memo {
    // 备份文档内容
    String content;
    // 构造方法
    public BackUp(String content) {
        this.content = content;
    }
}



public class Document {
    // 文档内容
    private String content;
    // 保存文档 方法 备份文档
    public BackUp save() {
        return new BackUp(content);
    }
    // 恢复备份方法
    public void resume(BackUp backUp) {
        content = backUp.content;
    }
    // 改变方法
    public void change(String content) {
        this.content = content;
    }
    // 打印文档方法
    public void print() {
        System.out.println("文档内容为: "+ content);
    }
}



// 历史记录类
public class History {
    // 创建备忘录栈
    Stack<BackUp> stack = new Stack<>();
    // 备忘录栈添加方法
    public void add(BackUp backUp) {
        stack.add(backUp);
    }
    // 备忘录读取方法
    public BackUp getVersion() {
        return stack.pop();
    }

}


public class Test {
    public static void main(String[] args) {
        // 创建备忘录栈
        History history = new History();
        // 创建文档类
        Document document = new Document();
        document.change("第一次改变文档内容");
        history.add(document.save());
        document.print();

        document.change("第二次改变文档内容");
        document.print();

        document.resume(history.getVersion());
        document.print();

    }
}

十八、迭代器模式


十九、组合模式

1.概念

将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

2.组合模式应用

/**
 * 统计接口
 */
public interface Container {
    // 统计方法
    public int count();
}


/**
 * 城市 节点 
 */
public class City implements Container{
    // 城市人口数量
    private Integer sum;

    // 构造方法
    public City(Integer sum) {
        this.sum = sum;
    }

    @Override
    public int count() {
        System.out.println("统计完毕返回人数!");
        return sum;
    }
}




/**
 * 城市容器
 */
public class CityContainer implements  Container {

    // 城市集合
    private List<Container> containerList = new ArrayList<>();

    // 添加城市
    public void addCity(Container container) {
        containerList.add(container);
    }

    // 删除城市
    public void deleteCity(Container container) {
        containerList.remove(container);
    }

    // 查询城市集和
    public List<Container> getContainerList() {
        return containerList;
    }

    @Override
    public int count() {

        int sumPerson = 0;
        for (Container c: containerList) {
            sumPerson += c.count();
        }

        return sumPerson;
    }
}



public class Test {
    public static void main(String[] args) {
        // 中国
        CityContainer china = new CityContainer();

        // 上海
        Container shangHai = new City(10);
        // 山东
        CityContainer shanDong = new CityContainer();

        // 青岛
        Container qingDao = new City(20);
        // 烟台
        Container yanTai = new City(30);
        // 为山东添加城市
        shanDong.addCity(qingDao);
        shanDong.addCity(yanTai);

        // 为中国添加城市
        china.addCity(shangHai);
        china.addCity(shanDong);
        System.out.println("中国人口" + china.count());
        
    }

二十、桥接模式

1.概念

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

2.桥接模式应用

java设计模式在工作中真的有应用吗 java设计模式及应用案例_System_06

服装 分为 衣服裤子两大类 衣服裤子需要相同的途径 就是生产到销售的过程

现在我们用组合模式将其转化

java设计模式在工作中真的有应用吗 java设计模式及应用案例_java_07


就是将 生产与销售单独剥离出来用一个公共抽象类或者接口去继承或者实现

二十一、中介者模式

1.概念

定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。

2.中介者模式应用

/**
 * 婚姻介绍所 接口
 */
public interface Agency {
    // 注册会员
    void register(Person person);
    // 为会员配对
    void pair(Person person);
}


/**
 * 参与人员类
 */
public class Person {
    // 姓名
    String name;
    // 年龄
    int age;
    // 1为男 2 为女
    int sex;
    // 婚姻介绍所
    Agency agency;

    public Person(String name, int age, int sex, Agency agency) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.agency = agency;
        agency.register(this);
    }

    // 配对方法
    public void findPerson() {
        agency.pair(this);
    }
}



public class AgencyImpl implements Agency {
    // 参与者集合
    private List<Person> personList = new ArrayList<>();

    @Override
    public void register(Person person) {
        personList.add(person);
    }

    @Override
    public void pair(Person person) {
        for (Person value : personList) {
            System.out.println(person.age +"+"+ value.age +"+"+ person.sex +"+"+ value.sex);
            if (person.age == value.age && person.sex != value.sex ) {
                System.out.println("配对成功:" + value.name);
            }
        }
    }
}




public class Test {
    public static void main(String[] args) {
        Agency agency = new AgencyImpl();

        Person zhangSan = new Person("张三", 20, 1, agency);
        Person liSi = new Person("李四", 20, 2, agency);
        Person wangWu = new Person("王五", 21, 2, agency);

        liSi.findPerson();
    }
}

二十二、访问者模式

1.概念

在访问者模式里,每个访问者表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。