Day24JavaSE——线程池&定时器&设计模式

Day24JavaSE——线程池&定时器&设计模式

Lock锁
线程间的等待唤醒机制
内存可见性问题 volatile(了解)
CAS 算法(了解)
死锁现象
线程池
定时器
设计模式

Lock锁

A:Lock锁的概述
	虽然我们可以理解同步代码块和同步方法的锁对象问题,
	但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
	为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
B:Lock和ReentrantLock
	void lock()
	void unlock()
public class Test1 {
    public static void main(String[] args) {
        /**
         * A:Lock锁的概述
         *     虽然我们可以理解同步代码块和同步方法的锁对象问题,
         *     但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
         *     为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
         * B:Lock和ReentrantLock
         *     void lock()
         *     void unlock()*/
        CellRunnable cellRunnable = new CellRunnable();
        Thread th1 = new Thread(cellRunnable, "窗口1");
        Thread th2 = new Thread(cellRunnable, "窗口2");
        Thread th3= new Thread(cellRunnable, "窗口3");
        th1.start();
        th2.start();
        th3.start();
    }
}
public class CellRunnable implements Runnable {
    //使用Lock锁实现买票
    static int ticket = 100;
    static ReentrantLock lock=new ReentrantLock();

    @Override
    public void run() {
        //加锁
        while (true){
            lock.lock();
            try {
                if (ticket>=1){
                    //模拟一下售票环境,有网络延迟
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第:" + (ticket--) + " 张票");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                //释放锁 不管有没有遇到异常 所必须释放
                lock.unlock();
            }
        }
    }
}

死锁现象

public class Test {
    public static void main(String[] args) {
        /** 死锁问题概述
        如果出现了同步嵌套,就容易产生死锁问题
        是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
        举例:    中国人和美国人一起吃饭
              中国人使用的筷子
              美国人使用的刀和叉
               中国人获取到了美国人的刀
                美国人获取到了中国人的一根筷子*/

        /**两线程同时启动,是并发的
       * 当true线程持有A锁时,B线程是不能持有A锁的
       * 所以true 线程和false同时持有了锁,
       * 当下一步要持有对方的锁时就必须等对方执行完逻辑并释放锁之后才能执行
       * 但是两个线程的以后的逻辑所要持有的锁都在对方手里,无法获得,也就无法执行完成释放锁
       * 形成了死锁*/
      MyThread th1 = new MyThread(true);
      MyThread th2 = new MyThread(false);
      th1.start();
      th2.start();
   }
}
public class MyThread extends Thread{
    boolean flag;
    public MyThread(boolean flag){this.flag=flag;}
    @Override
    public void run() {
        if (flag){
            synchronized (Utils.objA){
                System.out.println("true 线程持有了objA锁,进来执行了AAAA");
                synchronized (Utils.objB){
                    System.out.println("true 线程持有了B锁,进来执行了BBBB");
                }
            }
        }else {
            synchronized (Utils.objB){
                System.out.println("false 线程持有了objB锁,进来执行了BBBB");
                synchronized (Utils.objA){
                    System.out.println("false 线程持有了objA锁,进来执行了AAAA");
                }
            }
        }
    }
}
public interface Utils {
    //创建两个对象,来充当两把锁对象
    public static final Object objA=new Object();
    public static final Object objB=new Object();
}

线程间的等待唤醒机制

Object 类中
  void wait ()  在其他线程调用此对象的 notify () 方法或 notifyAll () 方法前,导致当前线程等待。
 void wait (long timeout) 在其他线程调用此对象的 notify () 方法或 notifyAll () 方法,或者超过指定的时间量前,导致当前线程等待。
   void notify () 唤醒在此对象监视器上等待的单个线程。
   void notifyAll ()  唤醒在此对象监视器上等待的所有线程。 

内存可见性问题 volatile(了解)

volatile 解决内存可见性问题
	 一、Java内存模型
	 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的。
	 Java内存模型规定了所有的变量都存储在主内存中。每条线程中还有自己的工作内存,
	 线程的工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来)。
	 线程对变量的所有操作(读取,赋值)都必须在工作内存中进行。
	 不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。

	 3.Java中的可见性
	
	 对于可见性,Java提供了volatile关键字来保证可见性。
	 当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
	 而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,
	 当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。
	 另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,
	 并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。
	 
volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。
 	           相较于 synchronized 是一种较为轻量级的同步策略。
               
volatile 变量,用来确保将变量的更新操作通知到其他线程。
可以将 volatile 看做一个轻量级的锁,但是又与
锁有些不同:
 对于多线程,不是一种互斥关系
 不能保证变量状态的“原子性操作”               

CAS 算法(了解)

CAS 算法
 CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器
操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并
发访问。
 CAS 是一种无锁的非阻塞算法的实现。
 CAS 包含了 3 个操作数:
 需要读写的内存值 V
 进行比较的值 A
 拟写入的新值 B
 当且仅当 V 的值等于 A 时, CAS 通过原子方式用新值 B 来更新 V 的
   值,否则不会执行任何操作。
  jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronouse同步锁的一种乐观锁。JDK 5之前Java语言是靠synchronized关键字保证同步的,这是一种独占锁,也是是悲观锁。
  
 java.util.concurrent.atomic 包下提供了一些原子操作的常用类:
 AtomicBoolean 、 AtomicInteger 、 AtomicLong 、 AtomicReference
 AtomicIntegerArray 、 AtomicLongArray
 AtomicMarkableReference
 AtomicReferenceArray 

线程的状态转换图及常见执行情况(理解)

新建 , 就绪 , 运行 , 冻结 , 死亡
   新建:线程被创建出来
   就绪:具有CPU的执行资格,但是不具有CPU的执行权
   运行:具有CPU的执行资格,也具有CPU的执行权
   阻塞:不具有CPU的执行资格,也不具有CPU的执行权
   死亡:不具有CPU的执行资格,也不具有CPU的执行权

线程池

//线程池:存储线程的容器,线程池可以复用管理线程对象
//程序启动一个新线程的成本是比较高的,因为他涉及到要与操作系统进行交互
//而使用线程池也可以很好的提高性能,尤其是当程序中要创建大量的生存期很短的线程时,更应该考虑使用线程池
//线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用
//在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池

//JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
/*public static ExecutorService newCachedThreadPool():根据任务的数量来创建线程对应的线程个数
        * public static ExecutorService newFixedThreadPool(int nThreads):固定初始化几个线程
        * public static ExecutorService newSingleThreadExecutor():初始化一个线程的线程池
        * 这些方法的返回值是ExecutorService对象,该对象表示一个线程池
        * 可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
        * Future<?> submit(Runnable task)
        * <T> Future<T> submit(Callable<T> task)
        * 使用步骤:
        * 创建线程池对象
        * 创建Runnable实例
        * 提交Runnable实例
        * 关闭线程池*/
public class Test1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //ExecutorService 线程池对象
        ExecutorService executorService = Executors.newCachedThreadPool();
        /* executorService.submit(new MyRunnale());*/
        Future<?> submit = executorService.submit(new MyRunnable());
        Future<Integer> submit1 = executorService.submit(new MyCellable());
        System.out.println(submit1.get());

        //关闭线程池
        executorService.shutdown();
    }
}
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程执行了这个任务");
    }
}
public class MyCellable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("call方法执行了");
        return 100;
    }
}

固定几个线程并用匿名内部类创建线程

public class Test2 {
    public static void main(String[] args) {
        /*public static ExecutorService newFixedThreadPool(int nThreads):固定初始化几个线程*/
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //因为只固化了两个线程,所以两个以上都会重复使用原线程池里的两个线程
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"th1执行了");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"th2执行了");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"th1执行了");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"th1执行了");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"th1执行了");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"th1执行了");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"th1执行了");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"th1执行了");
            }
        });
        executorService.shutdown();
    }
}

初始化一个线程

public class Test1 {
    public static void main(String[] args) {
        // public static ExecutorService newSingleThreadExecutor ():初始化一个线程的线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "  111111111");
            }
        });

        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "  22222222");
            }
        });
    }
}

定时器

//Timer定时器,JDK提供的一种工具,线程用其安排以后在后台线程中执行的任务
        //可安排任务执行一次,或者定期重复执行

        /*Timer()
        * 创建一个新的计时器。
        * Timer(boolean isDaemon)
        * 创建一个新的定时器,其相关线程可以指定为 run as a daemon 。
        * Timer(String name)
        * 创建一个新的定时器,其相关线程具有指定的名称。
        * Timer(String name, boolean isDaemon)
        * 创建一个新的定时器,其相关线程具有指定的名称,可以指定为 run as a daemon 。
        * isDaemon - 如果关联的线程应该作为守护程序运行,则为true */
/*void cancel()
        * 终止此计时器,丢弃任何当前计划的任务。
        * int purge()
        * 从该计时器的任务队列中删除所有取消的任务。
        * void schedule(TimerTask task, Date time)
        * 在指定的时间安排指定的任务执行。
        * void schedule(TimerTask task, Date firstTime, long period)
        * 从指定 的时间开始 ,对指定的任务延长period时间重复的执行 。
        * void schedule(TimerTask task, long delay)
        * 在指定的延迟之后安排指定的任务执行。
        * void schedule(TimerTask task, long delay, long period)
        * 在指定 的延迟之后开始 ,重新执行 固定延迟执行的指定任务。
        * void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
        * 从指定的时间开始 ,对指定的任务间隔period时间重复执行。
        * void scheduleAtFixedRate(TimerTask task, long delay, long period)
        * 在指定的延迟之后开始,对指定的任务间隔period时间重复执行。*/

例程1

public class Test1 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //让定时器执行定时任务
        MyTimerTask myTimerTask = new MyTimerTask(timer);
        //等3秒之后执行
        //timer.schedule(myTimerTask,3000);
        //等3秒第一次执行任务,以后间隔1秒重复执行定时任务
        timer.schedule(myTimerTask,3000,2000);
        //取消定时任务
        myTimerTask.cancel();
        //取消定时器
        timer.cancel();
    }
}
public class MyTimerTask extends TimerTask {
    private Timer timer;

    public MyTimerTask(Timer timer) {
        this.timer = timer;
    }

    @Override
    public void run() {
        System.out.println("pong pong pong");
        //取消定时器
        //timer.cancel();
    }
}

例程2

public class Test {
    public static void main(String[] args) throws ParseException {
        Timer timer = new Timer();
        //在指定日期执行定时任务
        MyTask myTask = new MyTask();
        String dateStr="2020-06-19 00:43:00";
        //在指定日期执行定时任务
        Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
        //在指定日期执行定时任务一次
        //timer.schedule(myTask,date);
        //在指定日期第一次执行任务,以后间隔1s重复执行
        timer.schedule(myTask,date,1000);
    }
}
public class MyTask extends TimerTask {
    @Override
    public void run() {
        System.out.println("定时任务执行了!");
    }
}

例程3定时删除文件夹

public class Test {
    public static void main(String[] args) throws ParseException {
        Timer timer = new Timer();
        MyTask myTask = new MyTask();
        String s="2020-06-19 01:19:00";
        Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s);
        timer.schedule(myTask,date);
    }
}
public class MyTask extends TimerTask {
    @Override
    public void run() {
        File file = new File("C:\\Users\\Administrator\\Desktop\\新建文件夹");
        deleteFlord(file);
    }
    public void deleteFlord(File file){
        boolean deleteFlag = file.delete();
        if (!deleteFlag){
            File[] files = file.listFiles();
            for (File file1 : files) {
                if (!file1.delete()){
                    deleteFlord(file1);
                }
            }
        }
        file.delete();
    }
}

多线程常见面试题

A:多线程有几种实现方案,分别是哪几种? 三种
Thread类、Runnable接口、Callable接口
B:同步有几种方式,分别是什么? 
三种 同步代码块 同步方法,Lock
C:启动一个线程是run()还是start()?它们的区别?
启动线程用的是start()
调用run()相当于只调用了一个方法,这样的结果是不会出现线程之间的并发效果,而是顺序执行

设计模式

设计模式的概述和分类(了解)

A:设计模式概述
	设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编写、代码设计经验的总结。
	使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性以及代码的结构更加清晰.
B:设计模式分类
	创建型模式(创建对象的):	单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
	行为型模式(对象的功能):	适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
	结构型模式(对象的组成):	模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

简单工厂模式

例程1
public class Test {
    public static void main(String[] args) {
        /*//在普通的使用模式下,我们要使用类中的方法,就需要new对象,再去调用方法
        Animal cat = new Cat();
        Animal dog = new Dog();
        Animal tiger = new Tiger();
        cat.eat();
        dog.eat();
        tiger.eat();*/
        //在真正的工程使用中,不可能进行代码级操作
        //并且工程之中分模块编写,为了便于其他的同事进行整合需要用到设计模式
        /**设计模式分类
         * 创建型模式(创建对象的):   单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
         *     行为型模式(对象的功能):  适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
         *     结构型模式(对象的组成):  模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式
         *     备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。*/
        //简单工厂模式
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        Animal animal = AnimalFactory.getAnimal(s);
        animal.eat();
    }
}
//定义顶层父类
public abstract class Animal {
    public abstract void eat();
}
//工厂类:主要负责创建各种动物对象
public class AnimalFactory {
    private AnimalFactory(){}
    public static Animal getAnimal(String name){
        if ("cat".equals(name)){
            return new Cat();
        }else if ("dog".equals(name)){
            return new Dog();
        }else if ("tiger".equals(name)){
            return new Tiger();
        }else {
            return null;
        }
    }
}
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}
public class Tiger extends Animal{
    @Override
    public void eat() {
        System.out.println("老虎吃小动物");
    }
}
例程2

每个子类都有一个专门的类来返回其对象

//定义顶层父类
public abstract class Animal {
    public abstract void eat();
}
public interface BigFactory {
    //创建产品的方法
    Animal createAnimal();
}
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class CatFactory implements BigFactory{
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}
public class DogFactory implements BigFactory{
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
public class Tiger extends Animal{
    @Override
    public void eat() {
        System.out.println("老虎吃小动物");
    }
}
public class TigerFactory implements BigFactory{
    @Override
    public Animal createAnimal() {
        return new Tiger();
    }
}
public class Test {
    public static void main(String[] args) {
        Animal an = new DogFactory().createAnimal();
        an.eat();
        an = new CatFactory().createAnimal();
        an.eat();
        an = new TigerFactory().createAnimal();
        an.eat();
    }
}

单列式写法之懒汉式

public class Test {
    public static void main(String[] args) {
        //单列:保证一个类的对象,在内存中只有一个
        //单列模式:懒汉式、饿汉式
        //1、把该类的构造私有,使其不能在外界直接new对象
        Student student = Student.getStudent();
        Student student1 = Student.getStudent();
        System.out.println(student == student1);
    }
}

public class Student {
    //懒汉式写法:你要用这个对象的时候,再去创建
    private static Student student=null;
    //私有构造
    private Student(){}
    //2、提供静态方法,返回一个该类的实例,供外界使用
    //多线程环境下能保证这个方法的一定是创建一个对象吗?
    //加上synchronized保证多线程环境下的使用也是单列的
    //th1 th2
    public synchronized static Student getStudent(){
        //没有该类的实例时才创建该类的实例
        if (student==null){
            //th1   th2
            student = new Student();
        }
        return student;
    }
}

单列式写法之饿汉式

public class Test {
    public static void main(String[] args) {
        Teacher teacher = Teacher.getTeacher();
        Teacher teacher1 = Teacher.getTeacher();
        System.out.println(teacher == teacher1);
    }
}

public class Teacher {
    //饿汉式:这个类一加载就创建一个该类的对象
    private static Teacher teacher=new Teacher();
    //私有构造
    private Teacher(){}
    public static Teacher getTeacher(){return teacher;}
}

单例模式的Java代码体现Runtime类(理解)

Runtime类概述
	每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。 
	应用程序不能创建自己的 Runtime 类实例。 
B:案例演示:	public Process  exec(String command)  //执行Dos 命令
public class Test {
    public static void main(String[] args) throws IOException {
        /*每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。
        可以通过 getRuntime 方法获取当前运行时。
        应用程序不能创建自己的 Runtime 类实例。 */
        //public Process  exec(String command)  //执行Dos 命令
        // Runtime 这个类Java就采用的是单列模式的饿汉式
        Runtime runtime = Runtime.getRuntime();
        //可以执行一些DOS命令
        runtime.exec("calc");
        runtime.exec("mspaint");
        //定时关机
    }
}
public class Test2 {
    public static void main(String[] args) {

    }
}

class Mytask extends TimerTask{
    private Timer timer;
    public Mytask(Timer timer){this.timer=timer;}
    @Override
    public void run() {
        //定时关机
        Runtime runtime = Runtime.getRuntime();
        try {
            runtime.exec("shutdown /s /t 0");
            timer.cancel();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

模版设计模式概述和使用

/**A: 需求: 计算一个for循环执行的时间
         * B:模版设计模式概述
         *     模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现
         * C:优点和缺点
         *     a:优点:  使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求
         *     b:缺点:  如果算法骨架有修改的话,则需要修改抽象类*/
public class Test {
    public static void main(String[] args) {
        //单列设计模式
        //计算for循环的耗时
        //new CalcClass().calcFor();
        CycleClass cycFor = new CycFor();
        cycFor.CycTime();
        CopyFile copyFile = new CopyFile();
        copyFile.CycTime();
    }
}
public abstract class CycleClass {
    public void CycTime(){
        //算法骨架
        long start = System.currentTimeMillis();
        cycleMethod();
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - start) + "ms");
    }
    public abstract void cycleMethod();
}

public class CycFor extends CycleClass{
    //具体的功能在这里实现,算法在父类中实现
    @Override
    public void cycleMethod() {
        for (int i = 0; i < 2000; i++) {
            System.out.println("aaa");
        }
    }
}

public class CopyFile extends CycleClass{
    //具体的功能在这里实现,算法在父类中实现
    @Override
    public void cycleMethod() {
        System.out.println("复制了文件");
    }
}

装饰模式概述和使用

/**A:装饰模式概述:   装饰模式就是使用被装饰类的一个子类的实例,在客户端将这个子类的实例交给装饰类。是继承的替代方案
         * B:优点和缺点
         *     a:优点
         *        使用装饰模式,可以提供比继承更灵活的扩展对象的功能,它可以动态的添加对象的功能,
         *        并且可以随意的组合这些功能。
         *     b:缺点:  正因为可以随意组合,所以就可能出现一些不合理的逻辑。*/
public class Test {
    public static void main(String[] args) {
        Iphone iphone = new Iphone();
        iphone.call();
        System.out.println("===========================");
        MusicPhone musicPhone = new MusicPhone(iphone);
        musicPhone.call();
        System.out.println("===========================");
        VideoPhone videoPhone = new VideoPhone(iphone);
        videoPhone.call();
        System.out.println("===========================");
        VideoPhone videoPhone1 = new VideoPhone(new MusicPhone(iphone));
        videoPhone1.call();

        System.out.println("===========================");
        MusicPhone musicPhone1 = new MusicPhone(new VideoPhone(iphone));
        musicPhone1.call();

        System.out.println("===========================");
        MusicPhone musicPhone2 = new MusicPhone(new VideoPhone(new GamePhone(iphone)));
        musicPhone2.call();
    }
}
public interface Phone {
    //定义一个产品接口,定义产品的最基本功能
    void call();
}

public class BZPhone implements Phone{
    private Phone phone;
    //你要包装那个类,就把该类传过来
    public BZPhone(Phone phone){this.phone=phone;}
    @Override
    public void call() {
        this.phone.call();
    }
}

public class Iphone implements Phone{
    //具体的产品
    @Override
    public void call() {
        System.out.println("打电话");
    }
}

public class GamePhone extends BZPhone{
    public GamePhone(Phone phone) {
        super(phone);
    }

    @Override
    public void call() {
        super.call();
        System.out.println("游戏功能");
    }
}

public class MusicPhone extends BZPhone{
    public MusicPhone(Phone phone) {
        super(phone);
    }

    @Override
    public void call() {
        super.call();
        System.out.println("音乐功能");
    }
}

public class VideoPhone extends BZPhone{
    public VideoPhone(Phone phone) {
        super(phone);
    }

    @Override
    public void call() {
        super.call();
        System.out.println("视频功能");
    }
}

观察者模式概述和使用

public class Test {
    public static void main(String[] args) {
        /**A: 案例: 找猎头找工作
         * B: 观察者 = 订阅者 + 发布者
         *      岗位类  求职者  猎头(注册方法,注销方法,发布方法)*/
        JobSeeker zs = new JobSeeker("张三");
        JobSeeker ls= new JobSeeker("李四");
        JobSeeker ww= new JobSeeker("王五");
        //在猎头处注册
        Hunter hunter = new Hunter();
        hunter.addJobSeeker(zs);
        hunter.addJobSeeker(ls);
        hunter.addJobSeeker(ww);

        Job job= new Job("Java开发工程师", 8000);
        hunter.addJob(job);
        System.out.println("=====================");
        Job job2 = new Job("前端开发工程师", 18000);
        hunter.addJob(job2);
        System.out.println("========================");
        //注销
        hunter.removeJobSeeker(ww);
        Job job3 = new Job("运维工程师", 5000);
        hunter.addJob(job3);
    }
}
public class Hunter {
    //定义两个集合,用来装求职者和工作岗位
    private ArrayList<JobSeeker> jobSeekers=new ArrayList<>();
    private ArrayList<Job> jobs = new ArrayList<>();
    //注册求助者
    public void addJobSeeker(JobSeeker jobSeeker){jobSeekers.add(jobSeeker);}
    //注册工作岗位
    public void addJob(Job job){
        jobs.add(job);
        //工作岗位过来之后,通知求职者
        notifyJobSeeker(job);
    }
    private void notifyJobSeeker(Job job) {
        for (JobSeeker jobSeeker : jobSeekers) {
            System.out.println(jobSeeker.getName()+"你好!有一份工作:"+job.getJobName()+"薪资:"+job.getSal()+"欢迎你前去面试");
        }
    }
    //注销
    public void removeJobSeeker(JobSeeker jobSeeker){
        jobSeekers.remove(jobSeeker);
    }
}

public class Job {
    private String jobName;
    private double sal;

    public Job() {
    }

    public Job(String jobName, double sal) {
        this.jobName = jobName;
        this.sal = sal;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }
}

public class JobSeeker {
    private String name;

    public JobSeeker() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
.out.println(jobSeeker.getName()+"你好!有一份工作:"+job.getJobName()+"薪资:"+job.getSal()+"欢迎你前去面试");
        }
    }
    //注销
    public void removeJobSeeker(JobSeeker jobSeeker){
        jobSeekers.remove(jobSeeker);
    }
}

public class Job {
    private String jobName;
    private double sal;

    public Job() {
    }

    public Job(String jobName, double sal) {
        this.jobName = jobName;
        this.sal = sal;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }
}

public class JobSeeker {
    private String name;

    public JobSeeker() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值