java 23种设计模式

一、单例模式

采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法(静态方法)。

单例模式分为 八种、

饿汉:先给我 ,就是什么都创建好 等着被调用 可能造成内存浪费
懒汉:饿了在给我 就是:什么时候用 什么时候创建

  1. 饿汉式(静态常量)
  2. 饿汉式(静态代码块)
  3. 懒汉式(线程不安全)
  4. 懒汉式(线程安全,同步方法 效率低)
  5. 双重检查 (volatile synchronized) 建议使用
  6. 静态内部类 建议使用
  7. 枚举 建议使用

单例模式注意事项和细节说明

  1. 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使 用单例模式可以提高系统性能
  2. 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new

单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级 对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等)

1.1、饿汉式静态变量

实现步骤

  1. 构造器私有化 (防止 new )
  2. 本类的内部创建对象实例
  3. 提供一个公有的静态方法,返回实例对象
  • 优点:写法简单、在启动项目,类装载时 就完成了其实例化对象,避免线程同步的问题

  • 缺点:如果这个类对象用不到,但还是实例化了,造成了内存浪费

  • 结论:这种单例模式 可用,但 可能造成内存浪费,如果 这种单例太多,启动时一次性加载,啧啧啧,可怕的

public class A_SingletonPattern {

    public static void main(String[] args) {

        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        // 证明对象是同个对象
        System.out.println(instance == instance1); // true
        System.out.println("instance hashCode = " + instance.hashCode()); // instance hashCode = 789451787
        System.out.println("instance1 hashCode = " + instance.hashCode()); // instance1 hashCode = 789451787

    }
}
// 饿汉式(静态常量)
class Singleton{


    // 1、私有化 构造器
    private Singleton(){

    }

    // 2、类的内部创建对象实例
    private final static Singleton instance = new Singleton();

    // 3、提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance(){
        return instance;
    }



}

解读代码:
对 Singleton类
1、私有化构造器,防止new它

 // 1、私有化 构造器
    private Singleton(){

    }

2、类的内部创建对象实例 静态的且是常量 在启动项目是 就创建了该对象

   
    private final static Singleton instance = new Singleton();

3、提供一个公有的静态方法,返回实例对象

 public static Singleton getInstance(){
        return instance;
    }

main 方法 通过== 和 对象的hashcode 验证是同一个 Singleton 对象

    public static void main(String[] args) {

        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        // 证明对象是同个对象
        System.out.println(instance == instance1); // true
        System.out.println("instance hashCode = " + instance.hashCode()); // instance hashCode = 789451787
        System.out.println("instance1 hashCode = " + instance.hashCode()); // instance1 hashCode = 789451787

    }

1.2、饿汉式 静态代码块

class SingletonB {


    // 1、私有化 构造器
    private SingletonB() {

    }

    // 2、类的内部创建对象实例
    private static SingletonB instance;

    // 在静态代码块中,创建单例对象
    static {
        instance = new SingletonB();
    }

    // 3、提供一个公有的静态方法,返回实例对象
    public static SingletonB getInstance() {
        return instance;
    }
}

代码解读:
静态常量类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执 行静态代码块中的代码,初始化类的实例。

  // 2、类的内部创建对象实例
    private static SingletonB instance;

    // 在静态代码块中,创建单例对象
    static {
        instance = new SingletonB();
    }

1.3、懒汉式(单线程)

线程不安全 只能在单线程下使用

优缺点:

  1. 起到了 懒加载(Lazy Loading) 的效果,调用的时候再创建对象实例 但只能单线程下使用
  2. 如果在多线程下 ,一个线程第一个走到 if (instance == null) 这是需要创建一个对象,
    但是还没来得及往下走,另一个线程也走到这 也要去创建一个对象,这就会产生多个实例

结论:不要使用该方式 除非 上锁 synchronized 效率慢

    public static void main(String[] args) {

        SingletonC instance = SingletonC.getInstance();
        SingletonC instance1 = SingletonC.getInstance();
        // 证明对象是同个对象
        System.out.println(instance == instance1); // true
        System.out.println("instance hashCode = " + instance.hashCode()); // instance hashCode = 789451787
        System.out.println("instance1 hashCode = " + instance.hashCode()); // instance1 hashCode = 789451787


    }
}
class SingletonC{


    // 1、私有化 构造器
    private SingletonC(){

    }

    private static SingletonC instance;

    // 3、提供一个公有的静态方法,调用的时候 再创建该对象的实例
    public static SingletonC getInstance(){

        if (instance == null){
            instance = new SingletonC();
        }
        return instance;
    }



}

1.4、 懒汉式(线程安全)

优缺点:

  1. 解决线程安全问题
  2. 效率太低了 ,该方法每次只能有一个线程进入,效率降低

结论:不推荐使用这种方式

    public static void main(String[] args) {

        SingletonD instance = SingletonD.getInstance();
        SingletonD instance1 = SingletonD.getInstance();
        // 证明对象是同个对象
        System.out.println(instance == instance1); // true
        System.out.println("instance hashCode = " + instance.hashCode()); // instance hashCode = 789451787
        System.out.println("instance1 hashCode = " + instance.hashCode()); // instance1 hashCode = 789451787


    }
}
class SingletonD{
    // 1、私有化 构造器
    private SingletonD(){

    }

    private static SingletonD instance;

    // 3、提供一个公有的静态方法,加入synchronized 解决线程安全问题 效率 低
    public static synchronized SingletonD getInstance(){

        if (instance == null){
            instance = new SingletonD();
        }
        return instance;
    }
}

使用 synchronized 保证线程安全

1.5、双重检查

  • 优点: 线程安全 延迟加载 效率较高

  • 结论:推荐使用

上代码:

    public static void main(String[] args) {

        SingletonE instance = SingletonE.getInstance();
        SingletonE instance1 = SingletonE.getInstance();
        // 证明对象是同个对象
        System.out.println(instance == instance1); // true
        System.out.println("instance hashCode = " + instance.hashCode()); // instance hashCode = 789451787
        System.out.println("instance1 hashCode = " + instance.hashCode()); // instance1 hashCode = 789451787


    }
class SingletonE{

    // 1、私有化 构造器
    private SingletonE(){}

    private static volatile SingletonE instance;

    // 3、提供一个公有的静态方法,加入synchronized 同步代码块
    public static SingletonE getInstance(){

        if (instance == null){

            synchronized (SingletonE.class){
                if (instance == null){
                    instance = new SingletonE();
                }
            }
        }
        return instance;
    }
}

解读:
1、首先 私有化构造器 ,避免 外部 用new 创建此对象

 // 1、私有化 构造器
    private SingletonE(){}

2、其次 本类的对象置为全局参数,并 有 volatile 修饰

private static volatile SingletonE instance;

volatile:上个线程的操作对 后一个线程可见,保证 new 的时候不会发生指令重排

3、最后:
多线程情况下,一个线程 走进 synchronized 代码块中 判断为null 创建对象,
另一个线程 在同步代码块之外等待,因为volatile,上个线程 创建对象对该线程是可见的
所以 他的instance == null 不成立 直接返回 上个线程创建的对象。
双重检查是 两次判断本类对象是否为空

 // 3、提供一个公有的静态方法,加入synchronized 同步代码块
    public static SingletonE getInstance(){

        if (instance == null){

            synchronized (SingletonE.class){
                if (instance == null){
                    instance = new SingletonE();
                }
            }
        }
        return instance;
    }

1.6、静态内部类

优缺点说明

  1. 这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
  2. 静态内部类方式在 Singleton 类被装载时并不会立即实例化,而是在需要实例化时,调用 getInstance 方法,才 会装载 SingletonInstance 类,从而完成 Singleton 的实例化。
  3. 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM 帮助我们保证了线程的安全性,在类进行 初始化时,别的线程是无法进入的。
  4. 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
    结论:推荐使用.
    public static void main(String[] args) {

        SingletonF instance = SingletonF.getInstance();
        SingletonF instance1 = SingletonF.getInstance();
        // 证明对象是同个对象
        System.out.println(instance == instance1); // true
        System.out.println("instance hashCode = " + instance.hashCode()); // instance hashCode = 789451787
        System.out.println("instance1 hashCode = " + instance.hashCode()); // instance1 hashCode = 789451787


    }
}
class SingletonF{

    // 1、私有化 构造器
    private SingletonF(){}

    // 2、写一个静态内部类,该类中有静态属性
    private static class SingletonInstance{
        private static final SingletonF SINGLETON =new SingletonF();
    }

    // 3、提供一个静态公有方法,直接返回  SingletonInstance.SINGLETON
    public static SingletonF getInstance(){
        return SingletonInstance.SINGLETON;
    }



}

1.7、枚举方式

优缺点说明

  1. 这借助 JDK1.5 中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建 新的对象。
  2. 这种方式是 Effective Java 作者 Josh Bloch 提倡的方式

结论:推荐使用

    public static void main(String[] args) {
        SingletonG instance = SingletonG.INSTANCE;
        SingletonG instance1 =  SingletonG.INSTANCE;
        // 证明对象是同个对象
        System.out.println(instance == instance1); // true
        System.out.println("instance hashCode = " + instance.hashCode()); // instance hashCode = 789451787
        System.out.println("instance1 hashCode = " + instance.hashCode()); // instance1 hashCode = 789451787

        instance.sayOk();
    }
}

// 使用枚举方式 实现单例模式
enum SingletonG{
    INSTANCE;
    public void sayOk(){
        System.out.println("ok");
    }

}

单例模式在JDK的应用

java.lang.Runtime 就是经典的单例模式(饿汉式)
在这里插入图片描述

二、工厂模式

分为 三类:
1、简单工厂模式

工厂类为一个类。根据不同类型生成不同产品

2、工厂方法模式

工厂类为 抽象类 , 有不同的子类(子工厂)继承他,并重写 生成产品的方法,满足不同子工厂生成不同产品需求

3、抽象工厂模式

工厂类为接口 有不同的子类(子工厂)继承他,并重写 生成产品的方法,满足不同子工厂生成不同产品需求

2.1、 简单工厂模式

简单工厂模式

  1. 介绍:属于 创建型模式,工厂模式的一种。简单工厂模式 是由一个工厂对象决定创建除哪一种产品的实例,是工厂模式中最简单实用的模式
  2. 实现:定义一个创建对象的类,有这个类封装实例化对象的行为
  3. 使用:在 软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,会用到工厂模式

通过案例来解释 简单工厂模式
需求:要便于披萨种类的扩展,便于维护

  • 1、披萨的种类很多(GreekPizza、CheesePizza…)
  • 2、披萨的制作有 prepare(预备)、bake(烘,焙)、cut(切)、box(打包)
  • 3、完成披萨店订购功能

2.1.1、传统模式

先看下不使用 工厂模式的设计

public class ASimpleFactory {
    public static void main(String[] args) {
        Order order = new Order();
    }
}


// 抽象Pizza
@Data
abstract class Pizza {

    // 披萨名字
    protected String name;

    // 准备原材料 不同的披萨是不一样的 所以是 抽象方法
    public abstract void prepare();


    public void bake() {
        System.out.println(name + "baking");
    }

    public void cut() {
        System.out.println(name + "cutting");
    }

    public void box() {
        System.out.println(name + "boxing");
    }
}

class GreekPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("制作GreekPizza 准备原材料");
    }
}

class CheesePizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("制作 CheesePizza 准备原材料");
    }
}

// 1、新增披萨种类 胡椒披萨
class PepperPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("制作 PepperPizza 准备原材料");
    }
}

// 订购 披萨
class Order {

    // 构造器
    public Order() {

        Pizza pizza = null;
        String orderType;
        do {
            orderType = getType();
            if (orderType.equals("greek")) {
                pizza = new GreekPizza();
                pizza.setName("希腊 披萨");
            } else if (orderType.equals("cheese")) {
                pizza = new CheesePizza();
                pizza.setName("奶酪披萨");
            } else if (orderType.equals("pepper")) {
                // 2、新增 披萨种类
                pizza = new PepperPizza();
                pizza.setName("胡椒披萨");
            } else {
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);

    }

    // 获取用户订购披萨的种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }finally {

        }
    }
}

解释代码:
首先 披萨的制作有prepare(预备)、bake(烘,焙)、cut(切)、box(打包),其中只有 预备原材料是每个披萨都不同的操作
所以把 抽象一个披萨类 让每种 披萨 继承这个类 重写 预备的方法

// 抽象Pizza
@Data
abstract class Pizza {

    // 披萨名字
    protected String name;

    // 准备原材料 不同的披萨是不一样的 所以是 抽象方法
    public abstract void prepare();


    public void bake() {
        System.out.println(name + "baking");
    }

    public void cut() {
        System.out.println(name + "cutting");
    }

    public void box() {
        System.out.println(name + "boxing");
    }
}
class GreekPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("制作GreekPizza 准备原材料");
    }
}

class CheesePizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("制作 CheesePizza 准备原材料");
    }
}

// 1、新增披萨种类 胡椒披萨
class PepperPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("制作 PepperPizza 准备原材料");
    }
}

接下来是
用户手动输入订单类型的方法

    // 获取用户订购披萨的种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }finally {

        }
    }

最后 订单的操作:
Order类中的无参构造器,在new一个Order是 会调用这个无参构造器的方法,在此方法中,先获取订单的类型,根据类型判断调用 哪个披萨对象。

    public Order() {

        Pizza pizza = null;
        String orderType;
        do {
            orderType = getType();
            if (orderType.equals("greek")) {
                pizza = new GreekPizza();
                pizza.setName("希腊 披萨");
            } else if (orderType.equals("cheese")) {
                pizza = new CheesePizza();
                pizza.setName("奶酪披萨");
            } else if (orderType.equals("pepper")) {
                // 2、新增 披萨种类
                pizza = new PepperPizza();
                pizza.setName("胡椒披萨");
            } else {
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);

    }

主方法:

public static void main(String[] args) {
        Order order = new Order();
    }

传统模式:

  1. 优点:好理解、简单易操作
  2. 缺点:违反了 开闭原则 ,对扩展开放,对修改关闭,给类增加新的功能,尽量不改或稍改代码
    如:新增 披萨种类 需改两处代码

2.1.2、简单工厂模式

较于传统的模式 其 改进的思路:

把创建Pizza的对象封装到 一个类中,这样有新的种类,只需要修改该类即可

理解:简单工厂:
工厂生产 产品,所以单独有个工厂类 主要负责 制作产品,如 pizza 工厂 类 生成 pizza对象

public class BSimpleFactory {
    // 订购 披萨
    public static void main(String[] args) {
        new OrderB(new SimpleFactory());
    }
}

// 创建简单工厂类
class SimpleFactory{

    // 根据 orderType 返回 对应的披萨对象
    public PizzaB createPizza(String orderType){
        System.out.println("简单工厂模式");
        PizzaB pizza = null;
        if (orderType.equals("greek")) {
            pizza = new GreekPizzaB();
            pizza.setName("希腊 披萨");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizzaB();
            pizza.setName("奶酪披萨");
        } else if (orderType.equals("pepper")) {
            // 2、新增 披萨种类
            pizza = new PepperPizzaB();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }


}


// 抽象Pizza
@Data
abstract class PizzaB {

    // 披萨名字
    protected String name;

    // 准备原材料 不同的披萨是不一样的 所以是 抽象方法
    public abstract void prepare();


    public void bake() {
        System.out.println(name + "baking");
    }

    public void cut() {
        System.out.println(name + "cutting");
    }

    public void box() {
        System.out.println(name + "boxing");
    }
}

class GreekPizzaB extends PizzaB {

    @Override
    public void prepare() {
        System.out.println("制作GreekPizza 准备原材料");
    }
}

class CheesePizzaB extends PizzaB {

    @Override
    public void prepare() {
        System.out.println("制作 CheesePizza 准备原材料");
    }
}

// 1、新增披萨种类 胡椒披萨
class PepperPizzaB extends PizzaB {

    @Override
    public void prepare() {
        System.out.println("制作 PepperPizza 准备原材料");
    }
}

// 订购 披萨
class OrderB {
    // 定义一个简单工厂对象
    SimpleFactory simpleFactory;
    PizzaB pizza = null;

    // 这使用的是聚合 通过构造器传入 SimpleFactory 对象,也可以直接new这个对象(组合关系)
    public OrderB(SimpleFactory simpleFactory){
        setFactory(simpleFactory);
    }

    public void setFactory(SimpleFactory simpleFactory){
        this.simpleFactory = simpleFactory;

        String orderType = "";// 用户输入的
        do {
            orderType = getType();
            pizza = this.simpleFactory.createPizza(orderType);

            if (pizza != null){
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                System.out.println("订单失败");
                break;
            }
        }while (true);

    }




    // 获取用户订购披萨的种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }finally {

        }
    }
}


解读代码:
1、和传统模式一样 抽象pizza类 让各种pizza继承他重写预选原材料的方法。 以及获取用户输入披萨类型的方法。

2、重点来了
创建一个简单工厂类,由这个类 来决定 披萨类型(也就是工厂生产的产品类型),有制作披萨的方法

class SimpleFactory{

    // 根据 orderType 返回 对应的披萨对象
    public PizzaB createPizza(String orderType){
        System.out.println("简单工厂模式");
        PizzaB pizza = null;
        if (orderType.equals("greek")) {
            pizza = new GreekPizzaB();
            pizza.setName("希腊 披萨");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizzaB();
            pizza.setName("奶酪披萨");
        } else if (orderType.equals("pepper")) {
            // 2、新增 披萨种类
            pizza = new PepperPizzaB();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }


}

3、订单类
首先 定义成员变量 工程类对象 和披萨类对象

    SimpleFactory simpleFactory;
    PizzaB pizza = null;

有参构造器参数为 工厂类,这样 创建这个订单类对象的时候 就要传一个 工程类的对象

    // 这使用的是聚合 通过构造器传入 SimpleFactory 对象,也可以直接new这个对象(组合关系)
    public OrderB(SimpleFactory simpleFactory){
        setFactory(simpleFactory);
    }

然后 set方法 将传入的工厂类对象 给 成员变量(工厂类) 并且调用这个工厂类 的制作披萨的方法

  public void setFactory(SimpleFactory simpleFactory){
        this.simpleFactory = simpleFactory;

        String orderType = "";// 用户输入的
        do {
            orderType = getType();
            pizza = this.simpleFactory.createPizza(orderType);

            if (pizza != null){
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                System.out.println("订单失败");
                break;
            }
        }while (true);

    }

2.1.3、静态工厂

简单工厂模式 也叫 静态工厂模式

和 上述简单工厂只有这两处改动

1、工厂类 中方法为 静态方法

// 创建静态工厂类
class SimpleFactoryC{

    // 根据 orderType 返回 对应的披萨对象
    public static PizzaC createPizza(String orderType){
        System.out.println("简单工厂模式");
        PizzaC pizza = null;
        if (orderType.equals("greek")) {
            pizza = new GreekPizzaC();
            pizza.setName("希腊 披萨");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizzaC();
            pizza.setName("奶酪披萨");
        } else if (orderType.equals("pepper")) {
            // 2、新增 披萨种类
            pizza = new PepperPizzaC();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }
}

2、 改为静态方法的目的是 订单处 不需要工厂对象也可以调用该方法

    // 定义一个简单工厂对象
    PizzaC pizza = null;
    public OrderC(){
        String orderType = "";// 用户输入的
        do {
            orderType = getType();
            pizza = SimpleFactoryC.createPizza(orderType);

            if (pizza != null){
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                System.out.println("订单失败");
                break;
            }
        }while (true);

    }

2.2、工厂方法模式

1、看一个新的需求
披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,
比如 北京的奶酪 pizza、北京的胡椒 pizza 或 者是伦敦的奶酪 pizza、伦敦的胡椒 pizza

思路1、
使用简单工厂模式,创建不同的简单工厂类,比如 BJPizzaSimpleFactory、LDPizzaSimpleFactory 等等.
从当前 这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好

思路2
使用工厂方法模式

工厂方法模式 介绍:

  1. 工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类(子工厂)中具体实现。
    2) 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。

理解:

抽象工厂方法就是 首先有个抽象类为 总工厂。然后里面有个抽象方法, 由不同的子工厂继承这个类并且实现该抽象方法,从而得到需要的产品。如

代码:

public class AMethodFactory {
    public static void main(String[] args) {
        // 创建北京口味的Pizza
        new BJOrderPizza();
    }

}

// 抽象Pizza
@Data
abstract class Pizza {

    // 披萨名字
    protected String name;

    // 准备原材料 不同的披萨是不一样的 所以是 抽象方法
    public abstract void prepare();


    public void bake() {
        System.out.println(name + "baking");
    }

    public void cut() {
        System.out.println(name + "cutting");
    }

    public void box() {
        System.out.println(name + "boxing");
    }
}

class BJCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println("北京的奶酪pizza 准备原材料");
    }
}

class BJPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京的胡椒pizza");
        System.out.println("北京的胡椒pizza 准备原材料");
    }
}
class LDCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("伦敦的奶酪pizza");
        System.out.println("伦敦的奶酪pizza 准备原材料");
    }
}
class LDPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("伦敦的胡椒pizza");
        System.out.println("伦敦的胡椒pizza 准备原材料");
    }
}

// 披萨订单
abstract class OrderPizza{
    // 定义一个抽象 工厂方法,createPizza, 让各个工厂子类实现
    abstract Pizza createPizza(String orderType);

    // 构造器
    public OrderPizza(){
        Pizza pizza = null;
        String orderType;// 披萨类型
        do {
            orderType = getType();
            pizza = createPizza(orderType);
            // 制作过程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }while (true);
    }

    // 获取用户订购披萨的种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }finally {

        }
    }

}

// 工厂子类 北京Order
class BJOrderPizza extends OrderPizza{

    @Override
    Pizza createPizza(String orderType) {
        System.out.println("工厂方法模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

// 工厂子类 北京Order
class LDOrderPizza extends OrderPizza{

    @Override
    Pizza createPizza(String orderType) {
        System.out.println("工厂方法模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
                    pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

解读代码:

1、抽象pizza类 让各种pizza继承他重写预选原材料的方法

// 抽象Pizza
@Data
abstract class Pizza {

    // 披萨名字
    protected String name;

    // 准备原材料 不同的披萨是不一样的 所以是 抽象方法
    public abstract void prepare();


    public void bake() {
        System.out.println(name + "baking");
    }

    public void cut() {
        System.out.println(name + "cutting");
    }

    public void box() {
        System.out.println(name + "boxing");
    }
}

class BJCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println("北京的奶酪pizza 准备原材料");
    }
}

class BJPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京的胡椒pizza");
        System.out.println("北京的胡椒pizza 准备原材料");
    }
}
class LDCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("伦敦的奶酪pizza");
        System.out.println("伦敦的奶酪pizza 准备原材料");
    }
}
class LDPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("伦敦的胡椒pizza");
        System.out.println("伦敦的胡椒pizza 准备原材料");
    }
}

重点来啦
抽象 披萨订单 类 可以看作是总工厂,内有 抽象方法:制作pizza的方法,由各个工厂子类还实现该方法

// 披萨订单
abstract class OrderPizza{
    // 定义一个抽象 工厂方法,createPizza, 让各个工厂子类实现
    abstract Pizza createPizza(String orderType);

    // 构造器
    public OrderPizza(){
        Pizza pizza = null;
        String orderType;// 披萨类型
        do {
            orderType = getType();
            pizza = createPizza(orderType);
            // 制作过程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }while (true);
    }

    // 获取用户订购披萨的种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }finally {

        }
    }

}

// 工厂子类 北京Order
class BJOrderPizza extends OrderPizza{

    @Override
    Pizza createPizza(String orderType) {
        System.out.println("工厂方法模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

// 工厂子类 北京Order
class LDOrderPizza extends OrderPizza{

    @Override
    Pizza createPizza(String orderType) {
        System.out.println("工厂方法模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
                    pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

北京口味的披萨

public static void main(String[] args) {
        // 创建北京口味的Pizza
        new BJOrderPizza();
    }

2.3、抽象工厂模式

  1. 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
  2. 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
  3. 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
  4. 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应 的工厂子类。
    这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
public class aAbstractFactory {
    public static void main(String[] args) {
        new OrderPizza(new BJFactory());
    }
}

// 抽象Pizza
@Data
abstract class Pizza {

    // 披萨名字
    protected String name;

    // 准备原材料 不同的披萨是不一样的 所以是 抽象方法
    public abstract void prepare();


    public void bake() {
        System.out.println(name + "baking");
    }

    public void cut() {
        System.out.println(name + "cutting");
    }

    public void box() {
        System.out.println(name + "boxing");
    }
}

class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println("北京的奶酪pizza 准备原材料");
    }
}

class BJPepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的胡椒pizza");
        System.out.println("北京的胡椒pizza 准备原材料");
    }
}

class LDCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("伦敦的奶酪pizza");
        System.out.println("伦敦的奶酪pizza 准备原材料");
    }
}

class LDPepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("伦敦的胡椒pizza");
        System.out.println("伦敦的胡椒pizza 准备原材料");
    }
}

// 一个抽象工厂模式的抽象层
interface AbsFactory {

    // 让下面的工厂子类来具体实现
    public Pizza createPizza(String orderType);

}

// 北京的工厂子类
class BJFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("抽象工厂模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}
// 伦敦的工厂子类
class LDFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("抽象工厂模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

class OrderPizza{
    AbsFactory factory;

    // 构造器
    public OrderPizza(AbsFactory factory){
        setFactory(factory);
    }


    public void setFactory(AbsFactory factory){
        Pizza pizza = null;
        String orderType = ""; // 用户输入
        this.factory = factory;
        do {
            orderType = getType();
            // factory 可能是北京的工厂子类 也可能是 伦敦的工厂子类
            pizza = factory.createPizza(orderType);
            // 制作过程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }while (true);
    }

    // 获取用户订购披萨的种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }finally {

        }
    }
}

解读代码

1、抽象pizza类 让各种pizza继承他重写预选原材料的方法

// 抽象Pizza
@Data
abstract class Pizza {

    // 披萨名字
    protected String name;

    // 准备原材料 不同的披萨是不一样的 所以是 抽象方法
    public abstract void prepare();


    public void bake() {
        System.out.println(name + "baking");
    }

    public void cut() {
        System.out.println(name + "cutting");
    }

    public void box() {
        System.out.println(name + "boxing");
    }
}

class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println("北京的奶酪pizza 准备原材料");
    }
}

class BJPepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的胡椒pizza");
        System.out.println("北京的胡椒pizza 准备原材料");
    }
}

class LDCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("伦敦的奶酪pizza");
        System.out.println("伦敦的奶酪pizza 准备原材料");
    }
}

class LDPepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("伦敦的胡椒pizza");
        System.out.println("伦敦的胡椒pizza 准备原材料");
    }
}

重点来了
定义一个抽象总工厂 接口 。内有方法,由具体子工厂来实现该方法

// 一个抽象工厂模式的抽象层
interface AbsFactory {

    // 让下面的工厂子类来具体实现
    public Pizza createPizza(String orderType);

}

// 北京的工厂子类
class BJFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("抽象工厂模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}
// 伦敦的工厂子类
class LDFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("抽象工厂模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

订单类 成员变量为 接口AbsFactory ,由 有参构造器的参数也是AbsFactory,new的时候要传入AbsFactory对象
然后由set方法将传的AbsFactory对象赋值给 成员变量AbsFactory。

class OrderPizza{
    AbsFactory factory;

    // 构造器
    public OrderPizza(AbsFactory factory){
        setFactory(factory);
    }


    public void setFactory(AbsFactory factory){
        Pizza pizza = null;
        String orderType = ""; // 用户输入
        this.factory = factory;
        do {
            orderType = getType();
            // factory 可能是北京的工厂子类 也可能是 伦敦的工厂子类
            pizza = factory.createPizza(orderType);
            // 制作过程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }while (true);
    }

    // 获取用户订购披萨的种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }finally {

        }
    }
}

mian

public static void main(String[] args) {
        new OrderPizza(new BJFactory());
    }

工厂模式在 JDK中的应用

Calendar 类中,就使用了简单工厂模式

工厂模式小结

  1. 工厂模式的意义 将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项 目的扩展和维护性。
  2. 三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)
  3. 设计模式的依赖抽象原则

建议:

  1. 创建对象实例时,不要直接 new 类, 而是把这个 new 类的动作放在一个工厂的方法中,并返回。有的书上说, 变量不要直接持有具体类的引用。
  2. 不要让类继承具体类,而是继承抽象类或者是实现 interface(接口)
  3. 不要覆盖基类中已经实现的方法。

三、原型模式

原型模式:

就是将一个对象进行复制。深拷贝

Java 中 Object 类是所有类的根类,Object 类提供了一个 clone()方法,该方法可以将一个 Java 对象复制 一份,但是需要实现 clone 的 Java 类必须要实现一个接口 Cloneable,
该接口表示该类能够复制且具有复制的能力

比如:孙悟空 拔出猴毛,变出其他的孙悟空,一模一样

注意:

Cloneable的 clone方法对应 基本数据类型和String类型 是深拷贝
但是 对于 引用数据类型就是浅拷贝 ,不符合要求

public class BPrototype {

    public static void main(String[] args) {
        SheepB sheep1 = new SheepB("tom", 1, "白色");
        SheepB sheep2 = (SheepB)sheep1.clone();
        SheepB sheep3 = (SheepB)sheep1.clone();

        System.out.println(sheep1);
        System.out.println(sheep2);
        System.out.println(sheep3);
    }
}

@Data
class SheepB implements Cloneable{
    String name;
    int age;
    String color;

    public SheepB(String name, int age, String color) {
        this.age = age;
        this.name = name;
        this.color = color;
    }

    // 克隆 该对象,使用 默认的clone 方法来完成
    @Override
    protected Object clone(){


        SheepB sheepB = null;
        try {
            sheepB = (SheepB)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }


        return sheepB;
    }
}

解读代码:
需要copy的类 实现 Cloneable接口 并重写其clone方法()

  // 克隆 该对象,使用 默认的clone 方法来完成
    @Override
    protected Object clone(){


        SheepB sheepB = null;
        try {
            sheepB = (SheepB)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }


        return sheepB;
    }

深拷贝 和 浅拷贝

深拷贝
不仅复制对象的基本类,同时也复制原对象中的对象.就是说完全是新对象产生的.

浅拷贝
只复制对象的基本类型,对象类型,仍属于原来的引用

比如:B 复制 A

  • 浅拷贝:修改A 的值 B 的值也会改变 因为是同一个引用地址 : 克隆羊是浅拷贝
  • 深拷贝:不会改变,因为B 是一个新的对象,和A 没关系了

深拷贝的实现方法

  • 1、 重写 clone 实现深拷贝
  • 2、通过 对象序列化和反序列化实现深拷贝

3.1、重写 clone 实现深拷贝

  • 1、基本类型 和 String 之间用 默认的clone方法
  • 2、A类中有 引用对象B 就要套一下了
    首先在引用对象B 的类中也重写 clone,
    然后在A clone方法中,调用B的clone方法后 赋值给A 的引用对象B

缺点:
如果引用对象中还有引用的话,就很麻烦 这个方法不推荐

public static void main(String[] args) throws CloneNotSupportedException {

        DeepProtoType p = new DeepProtoType();
        p.name = "松江";
        p.deepCloneableTarget = new DeepCloneableTarget("大","小");

        DeepProtoType p2 = (DeepProtoType)p.clone();
        System.out.println(p.deepCloneableTarget.hashCode());
        System.out.println(p2.deepCloneableTarget.hashCode());
    }
}

class DeepCloneableTarget implements Cloneable {
    private String cloneName;
    private String cloneClass;

    //构造器
    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

    //因为该类的属性,都是 String , 因此我们这里使用默认的 clone 完成即可
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class DeepProtoType implements Cloneable {
    public String name; //String 属性
    public DeepCloneableTarget deepCloneableTarget;// 引用类型

    public DeepProtoType() {
        super();
    }

    //深拷贝 - 方式 1 使用 clone 方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        //这里完成对基本数据类型(属性)和 String 的克隆
        deep = super.clone();
        //对引用类型的属性,进行单独处理
        DeepProtoType deepProtoType = (DeepProtoType) deep;
        deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
        return deepProtoType;
    }
}


新对象引用对象和原引用对象的地址已经发生改变
在这里插入图片描述

3.2、深拷贝 通过对象的序列化和反序列化实现(推荐)

public class DPrototype {
    public static void main(String[] args) throws CloneNotSupportedException {

        DeepProtoTypeD p = new DeepProtoTypeD();
        p.name = "松江";
        p.deepCloneableTarget = new DeepCloneableTargetD("大", "小");

        DeepProtoTypeD p2 = (DeepProtoTypeD) p.deepClone();
        System.out.println(p.deepCloneableTarget.hashCode());
        System.out.println(p2.deepCloneableTarget.hashCode());
    }
}

class DeepCloneableTargetD implements Serializable{
    private String cloneName;
    private String cloneClass;

    //构造器
    public DeepCloneableTargetD(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }
}

class DeepProtoTypeD implements Serializable {
    public String name; //String 属性
    public DeepCloneableTargetD deepCloneableTarget;// 引用类型

    public DeepProtoTypeD() {
        super();
    }

    // 深拷贝 -方法2、通过对象的序列化和反序列化实现(推荐)
    Object deepClone() {
        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);//当前这个对象以对象流的方式输出

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepProtoTypeD copyObj = (DeepProtoTypeD) ois.readObject();
            return copyObj;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            return null;
        } finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                // TODO: handle exception
                System.out.println(e2.getMessage());
            }
        }
    }
}

四、建造者模式

产品和具体生产产品的细节 分开
建造者模式

  1. 又叫生成器模式,可以将复杂对象的建造过程抽取出来(抽象类别),使这个抽象过程的不同实现方式可以构造出不同表现的对象;
  2. 建造者模式 是一步一步创建一个复杂的对象,它允许用户值通过指定复杂对象的类型和内容就可以构建他们,用户不需要知道内部具体的构建细节
  • 如 造个汽车,我们只要知道把方向盘、轮胎等组装起来就ok,不需要知道 方向盘等 是怎么造出来的

建造模式的四个角色

  1. Product(产品角色):一个具体的产品对象,内含产品的属性
  2. 、Builder(抽象建造者):创建一个Product对象的各个部件指定的接口 (和 Product组合依赖【new 】)
  3. ConcreteBuilder(具体建造者):实现接口,产品的细节操作
  4. 、Director(指挥者):构建一个使用Builder接口的对象。【和 Builder 聚合依赖】

指挥者作用:

它主要是用于创建一个复杂的对象。 两个作用:1、隔离客户与对象的生产过程 2、负责控制产品对象的生产过程

案例:盖房子

  1. 需要建房子【产品】:这一过程为打桩、砌墙、封顶。【细节】
  2. 房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的.

首先看个 传统设计代码

public class ABuilderPattern {
    public static void main(String[] args) {
        new CommonHouse().build();
    }
}

// 抽象类房子
abstract class House{

    // 打地基
    abstract void buildBasic();
    // 砌墙
    abstract void buildWalls();
    // 封顶
    abstract void roofed();

    // 盖房子方法
    void build(){
        buildBasic();
        buildWalls();
        roofed();
    }
}

// 盖个普通的房子
class CommonHouse extends House {


    @Override
    void buildBasic() {
        System.out.println("普通房子打地基");
    }

    @Override
    void buildWalls() {
        System.out.println("普通房子砌墙");
    }

    @Override
    void roofed() {
        System.out.println("普通房子封顶");
    }
}


代码解读:
传统方式的问题分析

  1. 优点是比较好理解,简单易操作。
  2. 设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好.

也就是说,这种设计方案,把产 品(即:房子) 和 创建产品的过程(即:建房子流程) 封装在一起,耦合性增强了。

使用建造者模式

public class BBuilderPattern {
    public static void main(String[] args) {
        new HouseDirector(new BCommonHouse()).constructHouse();
    }

}


// 1、 Product产品角色(房子) 内含产品的属性
@Data
class BHouse{
    // 地基
    String basic;
    // 墙
    String wall;
    // 屋顶
    String roofed;

}

// 2、抽象建造者Build:创建一个Product对象的各个部件指定的接口(和 Product组合依赖【new 】)
// 建造房子的细节
abstract class HouseBuild{

    BHouse bHouse = new BHouse();

    // 打地基
    abstract void buildBasic();
    // 砌墙
    abstract void buildWalls();
    // 封顶
    abstract void roofed();

    // 建造完成房子,将产品(房子)返回
    BHouse build(){
        return bHouse;
    }
}

// 3、ConcreteBuilder(具体建造者)【普通房子】:实现接口,构建和装备各个部件
class BCommonHouse extends HouseBuild{
    @Override
    void buildBasic() {
        System.out.println("普通房子打地基");
    }

    @Override
    void buildWalls() {
        System.out.println("普通房子砌墙");
    }

    @Override
    void roofed() {
        System.out.println("普通房子封顶");
    }
}


// 3、ConcreteBuilder(具体建造者)【别墅】:实现接口,构建和装备各个部件
class BVillaHouse extends HouseBuild{
    @Override
    void buildBasic() {
        System.out.println("别墅打地基");
    }

    @Override
    void buildWalls() {
        System.out.println("别墅砌墙");
    }

    @Override
    void roofed() {
        System.out.println("别墅封顶");
    }
}


// 4、Director(指挥者):构建一个使用Builder接口的对象
//  房屋建造指挥者HouseDirector 和 HouseBuild 聚合依赖
class HouseDirector{

    HouseBuild houseBuild;

    public HouseDirector(HouseBuild houseBuild){
        this.houseBuild = houseBuild;
    }

    // 如何处理建造房子的流程,交给指挥者决定 ,造好返回产品(房子)
    public BHouse constructHouse(){
        houseBuild.buildBasic();
        houseBuild.buildWalls();
        houseBuild.roofed();
        return houseBuild.build();
    }

}

解读代码:
建造者模式的 四大角色

  1. Product产品角色(房子) 内含产品的属性
@Data
class BHouse{
    // 地基
    String basic;
    // 墙
    String wall;
    // 屋顶
    String roofed;

}
  1. 抽象建造者Build:创建一个Product对象的各个部件指定的接口(和 Product组合依赖【new 】)
    就是 抽象 盖房子的细节操作的方法
abstract class HouseBuild{

    BHouse bHouse = new BHouse();

    // 打地基
    abstract void buildBasic();
    // 砌墙
    abstract void buildWalls();
    // 封顶
    abstract void roofed();

    // 建造完成房子,将产品(房子)返回
    BHouse build(){
        return bHouse;
    }
}
  1. ConcreteBuilder(具体建造者)【普通房子、别墅】:实现接口,构建和装备各个部件.
// 3、ConcreteBuilder(具体建造者)【普通房子】:实现接口,构建和装备各个部件
class BCommonHouse extends HouseBuild{
    @Override
    void buildBasic() {
        System.out.println("普通房子打地基");
    }

    @Override
    void buildWalls() {
        System.out.println("普通房子砌墙");
    }

    @Override
    void roofed() {
        System.out.println("普通房子封顶");
    }
}


// 3、ConcreteBuilder(具体建造者)【别墅】:实现接口,构建和装备各个部件
class BVillaHouse extends HouseBuild{
    @Override
    void buildBasic() {
        System.out.println("别墅打地基");
    }

    @Override
    void buildWalls() {
        System.out.println("别墅砌墙");
    }

    @Override
    void roofed() {
        System.out.println("别墅封顶");
    }
}
  1. Director(指挥者):构建一个使用Builder接口的对象
    房屋建造指挥者HouseDirector 和 HouseBuild 聚合依赖
// 4、Director(指挥者):构建一个使用Builder接口的对象
//  房屋建造指挥者HouseDirector 和 HouseBuild 聚合依赖
class HouseDirector{

    HouseBuild houseBuild;

    public HouseDirector(HouseBuild houseBuild){
        this.houseBuild = houseBuild;
    }

    // 如何处理建造房子的流程,交给指挥者决定 ,造好返回产品(房子)
    public BHouse constructHouse(){
        houseBuild.buildBasic();
        houseBuild.buildWalls();
        houseBuild.roofed();
        return houseBuild.build();
    }

}

实现房子产品 和 盖房子的细节 进行分离

五、适配器模式

什么是适配器:

  • 如 t-c的充电器线给苹果手机充电,就需要 一个转换器 tc输入连接转换器,苹果线输出 转换器 ,转换器就是适配器。

什么是适配器模式

  1. 将 A类的接口 转换为 期望 的另一个接口表示,让两个不匹配的两个类 可以在一起工作 别名 包装类 (wrapper)
  2. 属于 结构型模式
  3. 分为三类 类适配器模式、对象适配器模式 、接口适配器模式

功能:让不匹配的类 可以协调工作

注意事项

  1. 三种命名方式,是根据 src 是以怎样的形式给到 Adapter(在 Adapter 里的形式)来命名的。
  2. 类适配器:以类给到,在 Adapter 里,就是将 src 当做类,继承
    对象适配器:以对象给到,在 Adapter 里,将 src 作为一个对象,持有
    接口适配器:以接口给到,在 Adapter 里,将 src 作为一个接口,实现
  3. Adapter 模式最大的作用还是将原本不兼容的接口融合在一起工作。

案例
被适配:220V电压(Voltage) 充电器(适配器) 目的 5V电压 给手机充电

5.1、类适配器模式

介绍
Adapter类【适配器】,通过继承 src 类【被适配的累】,实现 dst类接口【目标类】,完成 src -> dst 的适配

适配器 获取 220Vde 电压 将其改为5V输出

public class AAdapterPattern {

    public static void main(String[] args) {
        System.out.println("类适配器模式");
        // 用适配器 给手机充电
        new Phone().charging(new VoltageAdapter());
    }
}

// 1、 被适配 220V电压
class Voltage220V{

    // 输出 220V的电压
    int output220V(){
        int src = 220;
        return src;
    }
}

// 2、设配接口 输出5V
interface Voltage5V{
    int out5V();
}

// 3、适配器类 将220V 电压 转换为 5V
class VoltageAdapter extends Voltage220V implements Voltage5V{

    @Override
    public int out5V() {
        // 拿到 220V 电压
        int srcV = output220V();
        // 适配器 将220转为5V
        int dstV = srcV / 44;
        return dstV;
    }
}

// 手机
class Phone{
    // 充电
    void charging(Voltage5V v){
        if (v.out5V() ==5){
            System.out.println("充电...");
        }else {
            System.out.println("NONONO");
        }
    }
}

代码解读
通过 设配器 VoltageAdapter 将 Voltage220V、Phone这两个不匹配的类 可以协调工作

  1. 被适配的类 220V电压
class Voltage220V{

    // 输出 220V的电压
    int output220V(){
        int src = 220;
        return src;
    }
}
  1. 目的类 接口 5V 电压
// 2、设配接口 输出5V
interface Voltage5V{
    int out5V();
}
  1. 适配器类 继承 被适配类Voltage220V 实现 目的 接口 Voltage5V
    重写 目的接口Voltage5V 的方法
    获取适配类 Voltage220V 的220电压 将其改为 5 V 进行输出
// 3、适配器类 将220V 电压 转换为 5V
class VoltageAdapter extends Voltage220V implements Voltage5V{

    @Override
    public int out5V() {
        // 拿到 220V 电压
        int srcV = output220V();
        // 适配器 将220转为5V
        int dstV = srcV / 44;
        return dstV;
    }
}

手机

// 手机
class Phone{
    // 充电
    void charging(Voltage5V v){
        if (v.out5V() ==5){
            System.out.println("充电...");
        }else {
            System.out.println("NONONO");
        }
    }
}

5.2、对象适配器模式

介绍

  1. 根据“合成复用原则”,在系统中尽量使用关联关系(聚合)来替代继承关系。
  2. 对象适配器模式是适配器模式常用的一种

基本思路
和类适配器类模式相同,只是将 设配器类修改,不是继承被适配类,而是持有被适配的类的对象【聚合方式】
即:持有 src类 实现dst类的接口 完成 src -> dst的适配

BVoltageAdapter 不再继承 BVoltage220V类,使用聚合 在BVoltageAdapter中传入 BVoltage220V类对象

public class BAdapterPattern {
    public static void main(String[] args) {
        System.out.println("对象适配器模式");
        // 用适配器 给手机充电
        new BPhone().charging(new BVoltageAdapter(new BVoltage220V()));
    }
}

// 1、 被适配 220V电压
class BVoltage220V{

    // 输出 220V的电压
    int output220V(){
        int src = 220;
        return src;
    }
}

// 2、设配接口 输出5V
interface BVoltage5V{
    int out5V();
}

// 3、对象适配器 将220V 电压 转换为 5V
class BVoltageAdapter implements BVoltage5V{

    BVoltage220V bVoltage220V;
    public BVoltageAdapter(BVoltage220V bVoltage220V){
        this.bVoltage220V = bVoltage220V;
    }

    @Override
    public int out5V() {
        int dstV = 0;
        if (null != bVoltage220V){
            // 拿到 220V 电压
            int srcV =bVoltage220V.output220V();
            // 适配器 将220转为5V
            dstV = srcV / 44;
        }
        return dstV;
    }
}

// 手机
class BPhone{
    // 充电
    void charging(BVoltage5V v){
        if (v.out5V() ==5){
            System.out.println("充电...");
        }else {
            System.out.println("NONONO");
        }
    }
}


代码解读:
通过 聚合的方法将 被适配器对象传入 进行操作,不再是用继承了

// 3、对象适配器 将220V 电压 转换为 5V
class BVoltageAdapter implements BVoltage5V{

    BVoltage220V bVoltage220V;
    public BVoltageAdapter(BVoltage220V bVoltage220V){
        this.bVoltage220V = bVoltage220V;
    }

    @Override
    public int out5V() {
        int dstV = 0;
        if (null != bVoltage220V){
            // 拿到 220V 电压
            int srcV =bVoltage220V.output220V();
            // 适配器 将220转为5V
            dstV = srcV / 44;
        }
        return dstV;
    }
}

5.3、接口适配模式

介绍

当不需要全部实现接口的方法时,可以先设计一个抽象的实现接口,
并为 该接口中的每个方法提供一个默认实现方法(空方法)
那么,该抽象类的子类 可以有选择的覆盖父类的某些方法 来实现需求。

适用
一个接口不想使用其所有方法的情况

如:
i4接口 有很多方法,B抽象类实现 i4 接口,并实现I接口的所有方法【空方法】
主方法创建 B的实例,并有选择的 重写 需要使用的 接口方法

public class CAdapterPattern {
    public static void main(String[] args) {
        B b = new B(){
            // 只需要重写需要使用的 接口方法

            @Override
            public void m1() {
                super.m1();
                System.out.println("使用了m1");
            }
        };
    }
}

interface i4{
    void m1();
    void m2();
    void m3();
    void m4();
}

abstract class B implements i4{
    @Override
    public void m1() {

    }

    @Override
    public void m2() {

    }

    @Override
    public void m3() {

    }

    @Override
    public void m4() {

    }
}

六、桥接模式

介绍

  1. Bridge 模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。
  2. 它的主要 特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的 功能扩展

案例

  1. 在对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网,打电话等)
  2. 手机分为折叠式,直立式 旋转式 ,每种又分为 华为、小米、vivo
public class ABridgePattern {
    public static void main(String[] args) {
        Phone p1 = new FoldedPhone(new XiaoMi());
        p1.open();
        p1.call();
        p1.close();
        System.out.println("=================");
        Phone p2 = new FoldedPhone(new Vivo());
        p2.open();
        p2.call();
        p2.close();

        System.out.println("=================");
        Phone p3 = new UpRightPhone(new Vivo());
        p3.open();
        p3.call();
        p3.close();
    }


}

/**
 * 品牌 接口
 */

interface Brand{
    // 开机
    void open();
    // 关机
    void close();
    // 打电话
    void call();
}

// 小米
class XiaoMi implements Brand{

    @Override
    public void open() {
        System.out.println("小米开机");
    }

    @Override
    public void close() {
        System.out.println("小米关机");
    }

    @Override
    public void call() {
        System.out.println("小米打电话");
    }
}

// Vivo
class Vivo implements Brand{

    @Override
    public void open() {
        System.out.println("Vivo开机");
    }

    @Override
    public void close() {
        System.out.println("Vivo关机");
    }

    @Override
    public void call() {
        System.out.println("Vivo打电话");
    }
}

// 抽象手机类
abstract class Phone{

    // 品牌 组合关系
    private Brand brand;

    // 构造器
    public Phone(Brand brand){
        super();
        this.brand = brand;
    }

    // 调用实现该手机的品牌的方法
    void open(){
        this.brand.open();
    }

    void close(){
        this.brand.close();
    }

    void call(){
        this.brand.call();
    }

}

/**
* 折叠手机 继承抽象类
 *
 * 如何实现桥接的
 *      折叠手机调用 open ,调用的是父类Phone的open,父类的open 调用的是 品牌的open
 *    == 折叠手机调用的 open  调用的是 品牌的open
*/

class FoldedPhone extends Phone{

    public FoldedPhone(Brand brand) {
        super(brand);
    }
    void open(){
        super.open();
        System.out.println("折叠手机");
    }
    void close(){
        super.close();
        System.out.println("折叠手机");
    }
    void call(){
        super.call();
        System.out.println("折叠手机");
    }
}

// 新增 一个 直立式 样式 只要多这个对象
class UpRightPhone extends Phone{

    public UpRightPhone(Brand brand) {
        super(brand);
    }
    void open(){
        super.open();
        System.out.println("直立手机");
    }
    void close(){
        super.close();
        System.out.println("直立手机");
    }
    void call(){
        super.call();
        System.out.println("直立手机");
    }
}

代码解读
1、定义接口 品牌类

interface Brand{
    // 开机
    void open();
    // 关机
    void close();
    // 打电话
    void call();
}

2、手机 实现 品牌

// 小米
class XiaoMi implements Brand{

    @Override
    public void open() {
        System.out.println("小米开机");
    }

    @Override
    public void close() {
        System.out.println("小米关机");
    }

    @Override
    public void call() {
        System.out.println("小米打电话");
    }
}

3、抽象手机类 并于品牌接口 组合关联

// 抽象手机类
abstract class Phone{

    // 品牌 组合关系
    private Brand brand;

    // 构造器
    public Phone(Brand brand){
        super();
        this.brand = brand;
    }

    // 调用实现该手机的品牌的方法
    void open(){
        this.brand.open();
    }

    void close(){
        this.brand.close();
    }

    void call(){
        this.brand.call();
    }

}

4、 折叠手机 继承手机类

class FoldedPhone extends Phone{

    public FoldedPhone(Brand brand) {
        super(brand);
    }
    void open(){
        super.open();
        System.out.println("折叠手机");
    }
    void close(){
        super.close();
        System.out.println("折叠手机");
    }
    void call(){
        super.call();
        System.out.println("折叠手机");
    }
}

关键来了:

  • 如何实现桥接的
    折叠手机调用 open ,调用的是父类Phone的open,父类的open 调用的是 品牌的open
    == 折叠手机调用的 open 调用的是 品牌的open
 Phone p1 = new FoldedPhone(new XiaoMi());
        p1.open();
        p1.call();
        p1.close();

注意事项和细节

  1. 实现了抽象和实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,这有助于 系统进行分层设计,从而产生更好的结构化系统。
  2. 对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了,其它的部分由具体业务来完成。
  3. 桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本。
  4. 桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设 计和编程
  5. 桥接模式要求正确识别出系统中两个独立变化的维度(抽象、和实现),因此其使用范围有一定的局限性,即需 要有这样的应用场景。

应用场景

  1. -JDBC 驱动程序
  2. -银行转账系统 转账分类: 网上转账,柜台转账,AMT 转账 转账用户类型:普通用户,银卡用户,金卡用户…
  3. -消息管理 消息类型:即时消息,延时消息 消息分类:手机短信,邮件消息,QQ 消息…

七、观察者模式

需求

  1. 气象站可以将每天测量到的温度,湿度,气压等等 以公告的形式发布出去(比如发布到自己的网站或第三方)。
  2. 需要设计开放型 API,便于其他第三方也能接入气象站获取数据。 WeatherData
  3. 提供温度、气压和湿度的接口
  4. 测量数据更新时,要能实时的通知给第三方

传统模式

public class AObserverPattern {


    public static void main(String[] args) {

        ///创建接入方 currentConditions
        CurrentConditions currentConditions = new CurrentConditions();
        //创建 WeatherData 并将 接入方 currentConditions 传递到 WeatherData 中
        WeatherData weatherData = new WeatherData(currentConditions);
        // 更新天气情况
        weatherData.setData(30, 150, 40);
        // 天气情况变化
        System.out.println("============天气情况变化=============");
        weatherData.setData(40, 160, 20);


    }
}


/**
 * 当前 天气情况  == 可以理解成网站 展示天气状态
 */
class CurrentConditions{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度


    // 更新天气情况: 由 weatherData 调用,使用的推送模式 修改天气信息
    public void update(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;

        display();
    }

    // 网站显示天气
    private void display() {

        System.out.println("===当前温度 ======" + temperature);
        System.out.println("===当前气压 ======" + pressure);
        System.out.println("===当前湿度 ======" + humidity);
    }


}


/**
 *  核心类
 *  1、包含最新的天气情况信息
 *  2、包含 CurrentConditions 对象
 *  3、一旦天气有变化,就主动调用 CurrentConditions的 update 方法,更新网站的天气状态
 */
@Data
class WeatherData{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度
    private CurrentConditions currentConditions; // 湿度

    public WeatherData(CurrentConditions currentConditions){
        this.currentConditions = currentConditions;
    }

    // 当数据有更新时,调用  serData,重置气象数据 并调用 dataChange接口
    public void setData(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        dataChange();
    }

    // 调用 网站的 更新接口 ,更新网站的信息
    public void dataChange(){
        currentConditions.update(getTemperature(),getPressure(),getHumidity());
    }
}

解读代码

1、首先是具体的天气信息 WeatherData类
setData 方法就是更新天气情况,调用 datachange()方法,就是 调用 网站的 更新信息。
监测的天气发生变化,对应的各个网站展示的天气情况,也要随之改变发生

/**
 *  核心类
 *  1、包含最新的天气情况信息
 *  2、包含 CurrentConditions 对象
 *  3、一旦天气有变化,就主动调用 CurrentConditions的 update 方法,更新网站的天气状态
 */
@Data
class WeatherData{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度
    private CurrentConditions currentConditions; // 湿度

    public WeatherData(CurrentConditions currentConditions){
        this.currentConditions = currentConditions;
    }

    // 当数据有更新时,调用  serData,重置气象数据 并调用 dataChange接口
    public void setData(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        dataChange();
    }

    // 调用 网站的 更新接口 ,更新网站的信息
    public void dataChange(){
        currentConditions.update(getTemperature(),getPressure(),getHumidity());
    }
}

2、外部网站展示天气状态

WeatherData 更新天气状态 会对应这个外部网站的 update 方法

/**
 * 当前 天气情况  == 可以理解成网站 展示天气状态
 */
class CurrentConditions{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度


    // 更新天气情况: 由 weatherData 调用,使用的推送模式 修改天气信息
    public void update(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;

        display();
    }

    // 网站显示天气
    private void display() {

        System.out.println("===当前温度 ======" + temperature);
        System.out.println("===当前气压 ======" + pressure);
        System.out.println("===当前湿度 ======" + humidity);
    }


}

4、主方法
创建

    public static void main(String[] args) {

        ///创建接入方 currentConditions
        CurrentConditions currentConditions = new CurrentConditions();
        //创建 WeatherData 并将 接入方 currentConditions 传递到 WeatherData 中
        WeatherData weatherData = new WeatherData(currentConditions);
        // 更新天气情况
        weatherData.setData(30, 150, 40);
        // 天气情况变化
        System.out.println("============天气情况变化=============");
        weatherData.setData(40, 160, 20);


    }
}

传统模式 缺点:
此时只有一个 网站接入 WeatherData ,如果再有个网站就要 写一个 和 CurrentConditions 一样的类,weatherData 里也要 再聚合一个 类对象。
违反了 opc原则

观察者模式

  • 1、Subject 接口 包含注册、移除 和通知的方法
  • 2、observer 观察者 接口
public class BObserverPattern {

    public static void main(String[] args) {
        WeatherDataInfo weatherDataInfo = new WeatherDataInfo();
        Baidu baidu = new Baidu();
        XinLang xinLang = new XinLang();
        // 创建 观察者
        weatherDataInfo.registerObserver(baidu);
        weatherDataInfo.registerObserver(xinLang);
        weatherDataInfo.setData(10,20,30);
        System.out.println("===移除百度====");
        // 移除 一个观察者
        weatherDataInfo.removeObserver(baidu);
        weatherDataInfo.setData(110,210,310);
    }
}


/**
 * 气象站
 * registerObserver :注册接入气象信息的网站
 * removeObserver : 移除 接入获取气象信息的网站
 * notifyObserver:天气变化 通知网站 更新气象信息
 *
 */
interface Subject{

    // 注册
    public void registerObserver(Observer o);

    // 移除
    public void removeObserver(Observer o);

    // 通知
    public void notifyObserver();
}

/**
 * 观察者 接口,由观察者(接入气象信息的网站)实现
 *
 */
interface Observer{
    public void update(float temperature,float pressure, float humidity);
}


/**
 * 观察者1号:新浪网站
 */
class XinLang implements Observer{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度


    // 更新天气情况: 由 weatherData 调用,使用的推送模式 修改天气信息
    public void update(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;

        display();
    }

    // 网站显示天气
    private void display() {

        System.out.println("=XinLang==当前温度 ======" + temperature);
        System.out.println("==XinLang=当前气压 ======" + pressure);
        System.out.println("==XinLang=当前湿度 ======" + humidity);
    }


}
class Baidu implements Observer{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度


    // 更新天气情况: 由 weatherData 调用,使用的推送模式 修改天气信息
    public void update(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;

        display();
    }

    // 网站显示天气
    private void display() {

        System.out.println("=Baidu==当前温度 ======" + temperature);
        System.out.println("==Baidu=当前气压 ======" + pressure);
        System.out.println("==Baidu=当前湿度 ======" + humidity);
    }


}
/**
 *  核心类
 *  1、包含最新的天气情况信息
 *  2、含义 观察者集合,使用 ArrayList 管理
 *  3、一旦天气有变化,就主动调用 arrayList,通知所有接入者更新网站的天气状态
 */
@Data
class WeatherDataInfo implements Subject{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度
    private ArrayList<Observer> observers; // 观察者 集合

    public WeatherDataInfo(){
        this.observers = new ArrayList<Observer>();
    }

    // 当数据有更新时,调用  serData,重置气象数据 并调用 dataChange接口
    public void setData(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        dataChange();
    }

    // 调用 网站的 更新接口 ,更新网站的信息
    public void dataChange(){
        notifyObserver();
    }

    // 注册一个观察者
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    // 移除一个观察者
    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    // 通知所有观察者
    @Override
    public void notifyObserver() {

        for (Observer ob : observers) {
            ob.update(this.temperature,this.pressure,this.humidity);
        }
    }
}

解读代码
1、首先 定义一个接口 Subject
让 气象局 监测的天气信息并且对外暴露的接口来继承

/**
 * 气象站
 * registerObserver :注册接入气象信息的网站
 * removeObserver : 移除 接入获取气象信息的网站
 * notifyObserver:天气变化 通知网站 更新气象信息
 *
 */
interface Subject{

    // 注册
    public void registerObserver(Observer o);

    // 移除
    public void removeObserver(Observer o);

    // 通知
    public void notifyObserver();
}

2、再定义一个接口 Observer
由观察者来继承,此处由 需要获取天气信息的网站 来继承

/**
 * 观察者 接口,由观察者(接入气象信息的网站)实现
 *
 */
interface Observer{
    public void update(float temperature,float pressure, float humidity);
}

3、创建一个类对象 新浪 需要获取 实时的天气信息 为 观察者 1号

/**
 * 观察者1号:新浪网站
 */
class XinLang implements Observer{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度


    // 更新天气情况: 由 weatherData 调用,使用的推送模式 修改天气信息
    public void update(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;

        display();
    }

    // 网站显示天气
    private void display() {

        System.out.println("=XinLang==当前温度 ======" + temperature);
        System.out.println("==XinLang=当前气压 ======" + pressure);
        System.out.println("==XinLang=当前湿度 ======" + humidity);
    }


}

4、核心类。气象局监测的天气信息类,

  • 1、包含最新的天气情况信息
  • 2、含义 观察者集合,使用 ArrayList 管理
  • 3、一旦天气有变化,就主动调用 arrayList,通知所有接入者更新网站的天气状态

继承 Subject 接口 重写 注册、 移除、通知的接口 ,所有的观察者 放进 list集合中,需要通知的话,遍历集合,调用每个观察者的 update方法

/**
 *  核心类
 *  1、包含最新的天气情况信息
 *  2、含义 观察者集合,使用 ArrayList 管理
 *  3、一旦天气有变化,就主动调用 arrayList,通知所有接入者更新网站的天气状态
 */
@Data
class WeatherDataInfo implements Subject{
    private float temperature; //温度
    private float pressure; // 气压
    private float humidity; // 湿度
    private ArrayList<Observer> observers; // 观察者 集合

    public WeatherDataInfo(){
        this.observers = new ArrayList<Observer>();
    }

    // 当数据有更新时,调用  serData,重置气象数据 并调用 dataChange接口
    public void setData(float temperature,float pressure, float humidity){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        dataChange();
    }

    // 调用 网站的 更新接口 ,更新网站的信息
    public void dataChange(){
        notifyObserver();
    }

    // 注册一个观察者
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    // 移除一个观察者
    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    // 通知所有观察者
    @Override
    public void notifyObserver() {

        for (Observer ob : observers) {
            ob.update(this.temperature,this.pressure,this.humidity);
        }
    }
}

5、主方法
创建 实时数据WeatherDataInfo对象,
将新浪观察者放进 WeatherDataInfo 的观察者集合中,serData 更新数据 ,相应新浪也会更新数据。
创建一个 百度的 观察者,同样操作

    public static void main(String[] args) {
        WeatherDataInfo weatherDataInfo = new WeatherDataInfo();
        Baidu baidu = new Baidu();
        XinLang xinLang = new XinLang();
        // 创建 观察者
        weatherDataInfo.registerObserver(baidu);
        weatherDataInfo.registerObserver(xinLang);
        // 更新天气信息
        weatherDataInfo.setData(10,20,30);
        System.out.println("===移除百度====");
        // 移除 一个观察者
        weatherDataInfo.removeObserver(baidu);
        weatherDataInfo.setData(110,210,310);
    }
}
java设计模式大体上分为三大类: 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。 行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 设计模式遵循的原则有6个: 1、开闭原则(Open Close Principle)   对扩展开放,对修改关闭。 2、里氏代换原则(Liskov Substitution Principle)   只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。 3、依赖倒转原则(Dependence Inversion Principle)   这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。 4、接口隔离原则(Interface Segregation Principle)   使用多个隔离的借口来降低耦合度。 5、迪米特法则(最少知道原则)(Demeter Principle)   一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 6、合成复用原则(Composite Reuse Principle)   原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值