Java实现23种设计模式教程(3)

举报
摸鱼打酱油 发表于 2022/04/01 22:39:23 2022/04/01
【摘要】 动态代理(JDK动态代理)要实现如上的结果,我们这次不用静态代理,而是用JDK动态代理其实所谓的动态代理,也就是不用写代理类了,而是又JDK底层通过反射在内存中帮你创建好了一个代理类public class logger implements loggers { /** * JDK动态代理: * 我们无需创建代理类,而是有JDK底层的反射帮我们在内存中自动创建 ...

动态代理(JDK动态代理)

要实现如上的结果,我们这次不用静态代理,而是用JDK动态代理

其实所谓的动态代理,也就是不用写代理类了,而是又JDK底层通过反射在内存中帮你创建好了一个代理类

public class logger implements loggers {
    /**
     * JDK动态代理:
     * 我们无需创建代理类,而是有JDK底层的反射帮我们在内存中自动创建
     */

    @Override
    public void writerlogger() {

        System.out.println("写入日志。。");


    }
}
public interface loggers {


    void writerlogger();




}

动态代理:

public class loggerProxyMain {

      private static logger logger=new logger();

    public static void main(String[] args) {

        /**
         * public static Object newProxyInstance(ClassLoader loader,
         *                                           Class<?>[] interfaces,
         *                                           InvocationHandler h)
         */
     loggers loggers= (com.design.proxy.dongtaiProxy.loggers) Proxy.newProxyInstance(logger.class.getClassLoader(), logger.class.getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                        第一个参数:被代理的类的对象
                        第二个参数:方法参数args
                         */
                        System.out.println("代理开始====");
                        //如果用代理实例调用方法,将会在这里执行
                        Object invoke = method.invoke(logger, args);//不返回这个对象的话,代理实例为null
                        System.out.println("代理结束");
                        return invoke; //返回代理实例,并返回到loggers对象中

                    }
                });

     //****注意:进入invoke方法是有前提的,就是我们要使用代理实例对象loggers,如果不使用它就不会进入到invoke方法中
        //输入logger对象也行,也可以让他进入invoke方法
//        System.out.println(loggers);

        /*
        当我们去调用代理的方法时,method.invoke就会监听到,并执行被代理的方法
         */
        loggers.writerlogger();



    }



}

装饰器模式

我们可以把装饰器分为主菜和配菜,配菜就是装饰器,而主菜就是被装饰的

公式:创建一个抽象类(作为被装饰者的父类),被装饰者类去继承它,然后创建装饰者抽象类并继承被装饰者的父类,再有装饰者子类去继承装饰者抽象类。

案例:

被装饰者的抽象类,在这里是最高的类

public abstract class breakFast {


    public abstract int cost(); //价格



}

被装饰者具体类

public class rice extends breakFast {
    /**
     * 主食:米饭
     */

    @Override
    public int cost() {
        return 5;
    }

 
}
public class noodles extends breakFast {
    /**
     *主食: 面条
     */

    @Override
    public int cost() {
        return 10;
    }


}

装饰者抽象类:继承与被装饰者的父类

public abstract class decorations extends breakFast{



    public abstract int cost(); //装饰者的钱

 
}

装饰者类

public class coke extends decorations {


    private breakFast breakFast;
    private final int COKE_COST=2; //coke的价格

    public coke(breakFast breakFast){
        this.breakFast=breakFast;
    }



    @Override
    public int cost() {
        return breakFast.cost()+COKE_COST;
    }
}
public class milk extends decorations {


    private breakFast breakFast;
    private final int MILK_COST=3; //milk的价格

    public milk(breakFast breakFast){
        this.breakFast=breakFast;
    }


    @Override
    public int cost() {
        return breakFast.cost()+MILK_COST;
    }


}

测试:

public class main {


    public static void main(String[] args) {
        rice rice = new rice(); //创建被装饰者对象
        milk milk = new milk(rice);//把被装饰者对象放到装饰者的构造方法上去

        System.out.println("rice:"+rice.cost());
        System.out.println("milk+rice:"+milk.cost());

        milk milk1 = new milk(milk);

        System.out.println("milk*2+rice"+milk1.cost());



    }
 
}

适配器模式

适配器模式:就是把原本互不兼容的两样东西或者格式,转换成可以兼容

比如说:家用电压是220v,但是我们手机充电不需要这么大的电压,我们这时候需要电源适配器(充电头),去适配这个电压,把220v适配成(比如:5v,11v等等)

再比如说:有一个方法只能接收int类型数据,但是我们接收到了一个String类型数据,int和String本身就是两个不相同的类型,所以说这个方法是接收不到String类型的,我们可以使用适配器,把String类型转换(适配)成int类型,这样这个方法就可以接收到这个String类型数据了。

类适配器

公式:适配器类要继承src(原来的类),并实现dest(目标)接口

首先创建适配器类,并运用上面的公式:

public class classAdapter extends srcClass implements destInterface{

    /**
     * 类适配器是有公式的
     * 公式:类适配器要继承源类,实现于目标接口
     * public class classAdapter extends srcClass implements destInterface
     *
     * srcClass:在这里是指家用电压220V
     * destInterface : 在这里是指我们想适配成多少v的电压,比如手机常用的电压 5v
     */

    @Override
    public int vivoBattery_5V() {
        int src = super.getSrc();
        int dest=src/44;
        return dest;
    }




}

源(src)类:

public class srcClass {

    private final int v=220; //家用电压


    //源类生成220v
    public int getSrc(){
        return v;
    }

}

目标接口:

public interface destInterface {


    int vivoBattery_5V(); //vivo手机想要多少伏的电压



}

测试:

public class Test {


    public static void main(String[] args) {

        classAdapter classAdapter = new classAdapter();

        int res = classAdapter.vivoBattery_5V();
        System.out.println("当前电压:"+res+"v");


    }

}

对象适配器

为什么会有对象适配器:我们的对象适配器都是在类适配器上优化的,类适配器的缺点是extends(继承),因为Java是单继承的,而我们的对象适配器不过就是把这个extends srcClass 优化成一个对象,通过构造器进行传入,然后通过这个对象进行调用srcClass的方法,而类适配器就是通过super关键字去调用方法。。

public class adapter  implements destInterface {

    private srcClass srcClass;  //把之前的类适配器的extends 源类,改成一个对象进行调用

    public adapter(srcClass srcClass){ //再通过构造器传入srcClass对象
        this.srcClass=srcClass;
    }

    @Override
    public int get10V() {
        int src = srcClass.getV();
        int dest=src/22;
        return dest;
    }
}
public interface destInterface {


    int get10V();



}
public class srcClass {

    private final int v=220;

    public int getV(){

        return v;
    }
  
}

public class Test {


    public static void main(String[] args) {

        adapter adapter = new adapter(new srcClass());
        int v = adapter.get10V();
        System.out.println(v);

    }

}

接口适配器

为何有接口适配器:我们上面说的两种适配器方式都有一个缺点:就是我们上面两种适配器都需要实现目标接口,当目标接口有多个适配方法时,我们都要对它进行实现,而我们不需要全部实现,只需要实现其中一个即可,我们的接口适配器就是为了解决这个问题的。

没有给接口方法默认实现时:

public interface dest {


    int adapter_5v();

    int adapter_10v();

    int adapter_20v();





}
public class adapter implements dest {


    @Override
    public int adapter_5v() {
        return 0;
    }

    @Override
    public int adapter_10v() {
        return 0;
    }

    @Override
    public int adapter_20v() {
        return 0;
    }
}

就需要全部进行实现,很复杂

public class srcClass {

    private final int v=220; //家用电压


    //源类生成220v
    public int getSrc(){
        return v;
    }
 

}
public interface dest {

    /**
     * 当接口适配的方法很多,但是我们不需要全部的进行实现,我们可以随便给他一个默认值,用default修饰
     * 当我们需要具体实现某个方法时,只需要重写对应的方法即可
     */

    default int adapter_5v(){

        return 0;
    }

     default int adapter_10v(){

        return 0;
     }

    default int adapter_20v(){
        return 0;
    }


}
public class adapter implements dest {

    private srcClass srcClass;

    public adapter(srcClass srcClass){
        this.srcClass=srcClass;
    }

    @Override
    public int adapter_10v() {
        int src = srcClass.getSrc();
        int res=src/22;
        return res;
    }



}
class main{


    public static void main(String[] args) {

        adapter adapter = new adapter(new srcClass());
        int i = adapter.adapter_10v();
        System.out.println(i);


    }

}

享元模式

享元模式:“享”是共享 ,“元”是对象 ,享元模式也就是一种利用共享技术对实例对象进行共享,提高实例对象的复用性,和节省资源的开销,减少对象的创建,应用在大量的“”相似“”对象,但是这些对象只有一些不同,我们可以用这个模式。

享元模式如何在定制相似的对象(对对象的数据进行修改):我们可以通过享元模式的简单工厂从HashMap/HashTable中get到,然后再用set方法对它进行定制。

何为相似的对象: 说白了也就是同一个类创建出来的对象就是相似的对象

案例:用户的网站界面属性(网站类型(type)、颜色(color),动态消息(message))

public abstract class website {

    /**
     * 总的网站抽象类
     */

    public abstract void setColor(String color);

    public abstract void setMessages(List<String> messages);

    public abstract void setRandomCode(String randomCode);


}
public class sina extends website {

    /**
     * 新浪网站
     */
    private final String type="新浪";
    private String color;
    private List<String> messages;
    private String randomCode; //随机码

    public sina() {
    }



    public String getType() {
        return type;
    }

    public String getColor() {
        return color;
    }


    public List<String> getMessages() {
        return messages;
    }


    public String getRandomCode() {
        return randomCode;
    }


    @Override
    public String toString() {
        return "sina{" +
                "type='" + type + '\'' +
                ", color='" + color + '\'' +
                ", messages=" + messages +
                ", randomCode='" + randomCode + '\'' +
                '}';
    }


    @Override
    public void setColor(String color) {
        this.color=color;
    }

    @Override
    public void setMessages(List<String> messages) {
        this.messages=messages;
    }

    @Override
    public void setRandomCode(String randomCode) {
        this.randomCode=randomCode;
    }
}

public class zhihu extends website {

    /**
     * 知乎
     */
    private final String type="知乎";
    private String color;
    private List<String> messages;
    private String randomCode;

    public zhihu() {
    }



    public String getType() {
        return type;
    }

    public String getColor() {
        return color;
    }



    public List<String> getMessages() {
        return messages;
    }



    public String getRandomCode() {
        return randomCode;
    }



    @Override
    public String toString() {
        return "zhihu{" +
                "type='" + type + '\'' +
                ", color='" + color + '\'' +
                ", messages=" + messages +
                ", randomCode='" + randomCode + '\'' +
                '}';
    }
    @Override
    public void setColor(String color) {
        this.color=color;
    }

    @Override
    public void setMessages(List<String> messages) {
        this.messages=messages;
    }

    @Override
    public void setRandomCode(String randomCode) {
        this.randomCode=randomCode;
    }
}

享元工厂(相当于简单工厂的升级版):

这边存在线程安全问题,因为getWebsiteByFactory方法不是原子操作,所以我们多线程环境下一定要加锁

public class simpleFactory {

    /**
     * 享元模式是需要简单工厂模式的
     */
    private Map<String,website> map=new HashMap<>(); //享元模式精髓
    private String[] colors={"red","blue","yellow","green","orange"};

    public  website getWebsiteByFactory(String type){
        if(type==null||type.equals("")) {
            return null;
        }else {
            website website = map.get(type);
            if(website==null){
                //用简单工厂模式来书写
                if(type.equals("新浪")){
                    sina sina = new sina();
                    Random random = new Random();
                    int index = random.nextInt(5);
                    sina.setColor(colors[index]);
                    int i = random.nextInt(1000);
                    ArrayList<String> list = new ArrayList<>();
                    list.add("hello"+i);
                    sina.setMessages(list);
                    sina.setRandomCode(String.valueOf(random.nextInt(9999)));
                    map.put(type,sina);
                    System.out.println("创建新浪网站对象成功");
                    return sina;

                }else if(type.equals("知乎")){
                    zhihu zhihu = new zhihu();
                    Random random = new Random();
                    zhihu.setColor(colors[random.nextInt(5)]);
                    ArrayList<String> list = new ArrayList<>();
                    list.add("hello"+random.nextInt(1000));
                    zhihu.setMessages(list);
                    zhihu.setRandomCode(String.valueOf(random.nextInt(9999)));
                    map.put(type,zhihu);
                    System.out.println("创建知乎网站成功");
                    return zhihu;
                }else {
                    return null;
                }

            }else {
                System.out.println("在享元模式的简单工厂中已经存在这个网站,所以直接获取到,没有重新创建对象");
                return website;
            }
 
        }
 
    }

}

测试:

public class main {


    private static final String[] websites={"新浪","知乎"};

    public static void main(String[] args) {

        simpleFactory simpleFactory = new simpleFactory(); //创建享元模式的简单工厂

        website s1 = simpleFactory.getWebsiteByFactory("新浪");
        System.out.println(s1); //会创建对象
        /**
         * 享元模式重要作用之一:定制对象
         */
        s1.setColor("利用享元模式定制对象");
        website s2 = simpleFactory.getWebsiteByFactory("新浪");
        System.out.println(s2); //不会创建对象,而是从map里面拿
        




        Random random = new Random();


//        for (int i = 0; i < 20; i++) {
//            new Thread(()->{
//                website website = simpleFactory.getWebsiteByFactory(websites[random.nextInt(2)]);
//                System.out.println(website);
//
//            }).start();
//        }




    }

}

输出结果:

创建新浪网站对象成功
sina{type='新浪', color='red', messages=[hello713], randomCode='2522'}
在享元模式的简单工厂中已经存在这个网站,所以直接获取到,没有重新创建对象
sina{type='新浪', color='利用享元模式定制对象', messages=[hello713], randomCode='2522'}

多线程环境下的问题

只需在getWebsiteByFactory方法上加锁即可

public class simpleFactory {

    /**
     * 享元模式是需要简单工厂模式的
     */
    private Map<String,website> map=new HashMap<>(); //享元模式精髓
    private String[] colors={"red","blue","yellow","green","orange"};

    public synchronized website getWebsiteByFactory(String type){

组合模式(树型结构)

组合模式的项目应用:实现多级菜单 、文件夹的管理

组合模式我们把它看成一种“树”型结构,固然后面我们在打印这些内容的时候是需要用递归的

因为组合模式是按照树形结构来组合的,所以也有树的特点(比如:叶子节点)

案例:利用组合模式来实现三级菜单。

定义组合模式的菜单组件接口,并定义添加、删除、展示结点方法:

public interface component {

    /**
     * 组件接口:所有菜单都要实现这个component(组件)接口
     * 组合模式所需方法:添加结点、删除结点、打印菜单
     */

    //需要给这个添加结点一个默认实现,因为我们的叶子结点不需要添加结点和删除结点这两个方法
    default void addNode(component component){
        throw new UnsupportedOperationException();//默认抛出不支持操作异常
    }

    default void deleteNode(component component){
        throw new UnsupportedOperationException();
    }

    //打印===都需要实现
    void showMenu();

 
}

菜单组件实现类(非叶子结点==第一、二级菜单):

一级菜单:

public class firstMenu implements component {
    /**
     * 一级菜单
     */
    private String name; //菜单名称
    private List<component> components;

    public firstMenu(String name){
        this.name=name;
        this.components=new ArrayList<>();
    }

    @Override
    public void addNode(component component) {
        components.add(component);
    }

    @Override
    public void deleteNode(component component) {
        components.remove(component);
    }

    @Override
    public void showMenu() {
        System.out.println("---"+this.getName()); //打印当前调用者的名称
        if(components.size()>0){
            for (component component : components) {
                component.showMenu(); //递归的调用这个showMenu方法
            }
        }

    }

    public String getName() {
        return name;
    }

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

    public List<component> getComponents() {
        return components;
    }

    public void setComponents(List<component> components) {
        this.components = components;
    }
}

二级菜单:

public class secondMenu implements component {
    /**
     * 二级菜单
     */
    private String name;
    private List<component> components;

    public secondMenu(String name){
        this.name=name;
        this.components=new ArrayList<>();
    }



    @Override
    public void addNode(component component) {
        components.add(component);
    }

    @Override
    public void deleteNode(component component) {
        components.remove(component);
    }

    @Override
    public void showMenu() {
        System.out.println("------"+this.getName());

        if(components.size()>0){
            for (component component : components) {
                component.showMenu();;
            }
        }


    }
    public String getName() {
        return name;
    }

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

    public List<component> getComponents() {
        return components;
    }

    public void setComponents(List<component> components) {
        this.components = components;
    }
}

三级菜单:(叶子节点),没有添加、删除结点方法

public class lastMenu implements component {

    private String name;

    /**
     * 最后一个菜单(三级菜单):不能添加和删除,因为它是树的叶子结点
     */

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


    @Override
    public void showMenu() {
        System.out.println("---------"+this.name);
    }
}

组合模式客户端代码:

public class client {

    /**
     * 组合模式客户端
     * @param args
     */

    public static void main(String[] args) {

        //创建一级菜单
        component f1=new firstMenu("用户列表");
        //创建二级菜单
        component s1=new secondMenu("用户信息");
        component s2=new secondMenu("用户权限");
        component s3=new secondMenu("用户好友");
        //创建三级菜单
        component l1=new lastMenu("信息修改");
        component l2=new lastMenu("信息删除");

        component l3=new lastMenu("修改权限");

        component l4=new lastMenu("添加好友");
        component l5=new lastMenu("删除好友");
        component l6=new lastMenu("修改好友信息");


        //进行组合
        f1.addNode(s1);
        f1.addNode(s2);
        f1.addNode(s3);

        s1.addNode(l1);
        s1.addNode(l2);

        s2.addNode(l3);

        s3.addNode(l4);
        s3.addNode(l5);
        s3.addNode(l6);

        //展示菜单
        f1.showMenu();

    }


}

输出结果:

---用户列表
------用户信息
---------信息修改
---------信息删除
------用户权限
---------修改权限
------用户好友
---------添加好友
---------删除好友
---------修改好友信息

外观模式

为什么会有外观模式?外观模式能解决什么?其实就是把其他对象调用方法封装到外观类上,我们只需要通过调用外观类的方法就可以调用其他类的方法

总结:外观模式(门面模式)说白了就是把多个不同对象(类)的方法归纳到一个门面类(外观类)中,这样省去频繁创建对象,核心就是门面类

使用两种方法实现案例“买水果问题”。。

传统方式(买水果问题):

苹果实体类:

public class apple {

    /**
     * 苹果实体类
     */

    private String id;
    private String name;

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

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "apple{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

public class banana {

    /**
     * 香蕉实体类
     */

    private String id;
    private String name;

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

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "banana{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

public class orange {
    /**
     * 橙子实体类
     */

    private String id;
    private String name;

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

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "orange{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

创建各自的商店:

public class appleStore {

    /**
     * 苹果专卖店
     */


    //买苹果
    public apple buyApple(){
        apple apple = new apple("苹果");
        apple.setId(UUID.randomUUID().toString().replaceAll("-",""));
        return apple;
    }

}

public class bananaStore {

    //香蕉实体店

    public banana buyBanana(){

        banana banana = new banana("香蕉");
        banana.setId(UUID.randomUUID().toString().replaceAll("-",""));
        return banana;

    }
}
public class orangeStore {

    //橙子实体店

    public orange buyOrange(){
        orange orange=new orange("橙子");
        orange.setId(UUID.randomUUID().toString().replaceAll("-",""));
        return orange;
    }


}

顾客买水果:

public class client {


    public static void main(String[] args) {

        //买苹果
        //1.创建苹果店对象
        appleStore appleStore = new appleStore();
        //2.购买
        apple apple = appleStore.buyApple();
        //买香蕉
        bananaStore bananaStore = new bananaStore();
        banana banana = bananaStore.buyBanana();
        //买橙子
        orangeStore orangeStore = new orangeStore();
        orange orange = orangeStore.buyOrange();

        System.out.println(apple);
        System.out.println(banana);
        System.out.println(orange);
    }


}

====================

总结:可以看出来使用传统方法买水果比较复杂,顾客需要创建各自的商店,再去购买。。。

外观模式(买水果问题):

上面实体类不变,只需要添加一个门面类(外观类)即可

核心(外观类):

public class myFacade {

    /**
     * 创建门面类(外观类)
     */
    //这几个变量也可以写成单例,这里暂且不写
    private appleStore appleStore;
    private bananaStore bananaStore;
    private orangeStore orangeStore;

    public myFacade(){
        //初始化对象
        this.appleStore=new appleStore();
        this.bananaStore=new bananaStore();
        this.orangeStore=new orangeStore();
    }

    /**
     * 精髓。。。
     * 使用外观模式的外观类来归纳方法,把多个类的方法归纳到一个外观类中
     * @return
     */
    //创建门面方法(外观方法),购买水果
    //买苹果
    public apple buyAppleByfacade(){
        apple apple = appleStore.buyApple();
        apple.setId(UUID.randomUUID().toString().replaceAll("-",""));
        return apple;
    }
    //买香蕉
    public banana buyBananaByfacade(){
        banana banana = bananaStore.buyBanana();
        banana.setId(UUID.randomUUID().toString().replaceAll("-",""));
        return banana;
    }
    //买橙子
    public orange buyOrangeByfacade(){
        orange orange = orangeStore.buyOrange();
        orange.setId(UUID.randomUUID().toString().replaceAll("-",""));
        return orange;
    }
 
}
public class client {


    public static void main(String[] args) {

        //创建已经归纳好方法的外观类
        myFacade myFacade = new myFacade();
        //购买水果
        apple apple = myFacade.buyAppleByfacade();
        banana banana = myFacade.buyBananaByfacade();
        orange orange = myFacade.buyOrangeByfacade();

        System.out.println(apple);
        System.out.println(banana);
        System.out.println(orange);


    }
}

这时候我们不需要创建商店了,只需要创建外观类调用买水果方法即可。

外观模式优点:假如水果有1000种,那么我们就要创建1000个对象,而使用外观模式,只需要创建一个外观类的对象即可,只需要1个对象。这样对比起来就相当明显了。。。。。。。。。。。。。。。。。。

桥接模式

使用桥接类和需要被桥接的接口进行桥接

案例:假设我们需要一个接口,用来连接mysql或者Oracle

public interface connection {


    public void connectDatasource();


}
public class connection_mysql implements connection {

    /*
     连接mysql数据源
     */
    @Override
    public void connectDatasource() {
        System.out.println("mysql数据源连接成功!!!");
    }
}
public class connection_oracle implements connection {

    /*
    连接Oracle数据源
     */
    @Override
    public void connectDatasource() {
        System.out.println("oracle数据源连接成功!!!");
    }
}

传统方式测试:

public class client_chuantong {


    public static void main(String[] args) {

        //传统方法调用接口方法
        connection connection=new connection_mysql();
        connection.connectDatasource();

        connection connection1=new connection_oracle();

        connection.connectDatasource();


    }

}

桥的抽象类:

public abstract class bridge {
    /**
     * 桥的抽象类
     */
    
    public abstract void connection();


}

桥的实现类

public class bridgeImpl extends bridge {

    /**
     * 核心
     * 使用了桥接模式之后,我们只需要创建桥接
     */
    private connection connection;

    //给对象注入
    public bridgeImpl(connection connection){
        this.connection=connection;
    }

    //桥接方法(桥接接口方法)
    @Override
    public void connection() {

        connection.connectDatasource();

    }
}

桥接测试:

public class client_bridge {


    public static void main(String[] args) {
        //使用桥接实现类调用被桥接的接口方法
        bridge bridge = new bridgeImpl(new connection_oracle());
        bridge.connection();
    }

}

观察者模式

既然有观察者,那么也就有被观察者。一个被观察者被多个观察者观察。比如说天气预报,天气预报就是被观察者,订阅了天气预报的人就是观察者,天气预报需要通知观察者。

被观察者接口:

public interface observerable {
    /**
     * 被观察者
     */

    //添加观察者
    public void addObserver(observer observer);
    //移除观察者
    public void removeObserver(observer observer);
    //通知所有观察者
    public void notifyAllObserver();



}

观察者接口:

public interface observer {

    /**
     * 观察者
     */

    //接收通知的方法
    public void getTianqi(tianqi tianqi);

}

被观察者(在这是天气预报):

public class tianqi implements observerable {

    /**
     * 被观察者 :天气预报
     */
    private String date;//日期
    private String wendu;//摄氏度
    private List<observer> observers; //管理所有观察者,以便通知观察者们(其实也就是调用观察者的接收通知方法)

    public tianqi(){
        this.observers=new ArrayList<>();
        this.date="2021/5/9";
        this.wendu="37°C";
    }

    public tianqi(String date, String wendu) {
        this.date=date;
        this.wendu=wendu;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getWendu() {
        return wendu;
    }

    public void setWendu(String wendu) {
        this.wendu = wendu;
    }

    @Override
    public void addObserver(observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyAllObserver() {
        if(observers.size()>0){
            for (int i = 0; i < observers.size(); i++) {
                observers.get(i).getTianqi(new tianqi(this.date,this.wendu));
            }
        }else{
            System.out.println("没有人订阅过天气预报。。。");
        }
    }


    @Override
    public String toString() {
        return "天气信息{" +
                "date='" + date + '\'' +
                ", wendu='" + wendu + '\'' +
                '}';
    }
}

观察者:

public class person implements observer {

    /**
     * 人:观察者
     */
    private String name; //观察者名字

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

    @Override
    public void getTianqi(tianqi tianqi) {
        System.out.println("当前用户名为:"+name+","+tianqi);


    }
}

客户端(测试):

public class client {


    public static void main(String[] args) {

        tianqi tianqi = new tianqi();

        tianqi.addObserver(new person("小明"));
        tianqi.addObserver(new person("小华"));

        tianqi.notifyAllObserver();

        System.out.println("=======修改后");

        tianqi.addObserver(new person("小刘"));
        tianqi.setDate("2021/5/10");
        tianqi.setWendu("15°C");
        tianqi.notifyAllObserver();

    }

}

备忘录模式

备忘录模式:可以用来备份数据和恢复

备忘录需要有三个类:需要备份的类、originator(生成需要备份的类的对象),存储数据和恢复数据的类

责任链模式

策略模式

模板模式

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。