设计模式学习笔记

1、单例模式

1.1、单例模式分类

在这里插入图片描述

1.2、单例模式代码实现

1.2.1、饿汉式单例模式
  1. 代码实现
/*
 2. 饿汉式单例模式
 3. 1、什么是饿汉式单例模式
 4. 一个类只有一个实列(不能通过new 来获取更多的对象)
 5. */
public class SingletonTest01 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleton();
        Singleton singleton2 = Singleton.getSingleton();
        System.out.println(singleton1==singleton2);
        System.out.println(singleton1.hashCode());
        System.out.println(singleton2.hashCode());
    }
}
class Singleton{
    /*第一步私有化构造器
     * */
    private Singleton(){

    }
    /*第二步创建自身的实例对象
     * final static 修饰符是必要的,静态常量会在类加载的时候,放到常量池里面,
     * 所以通过get方法获取到的对象实例是唯一的
     * */
    private final static Singleton singleton = new Singleton();

    /*通过get方法获取类自身的对象实列,这个方法必须通过static修饰否则无法通过类名访问
    * */
    public static Singleton getSingleton() {
        return singleton;
    }
}
  1. 优缺点
    在这里插入图片描述
1.2.2、懒汉式单例模式(线程不安全)
  1. 代码实现
/*懒汉式单例模式
 */
public class SingletonTest01 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleton();
        Singleton singleton2 = Singleton.getSingleton();
        System.out.println(singleton1==singleton2);
        System.out.println(singleton1.hashCode());
        System.out.println(singleton2.hashCode());
    }
}
class Singleton{
    /*第一步私有化构造器
     * */
    private Singleton(){

    }
    /*第二步创建自身的实例对象
     * static 修饰符是必要的,静态常量会在类加载的时候,放到常量池里面,
     * 所以通过get方法获取到的对象实例是唯一的
     * */
    private static Singleton singleton ;

    /*通过get方法获取类自身的对象实列,这个方法必须通过static修饰否则无法通过类名访问
    * */
    public static Singleton getSingleton() {
    	if(singleton ==null){
    		singleton = new Singleton(); 
    	}
        return singleton;
    }
}
  1. 优缺点
    在这里插入图片描述
  2. 改进是它线程安全(用synchronized加锁)
    这种写法解决了线程安全问题,但是使用synchronized 同步效率会很低,还不如牺牲点内存用饿汉式
public static synchronized Singleton getSingleton() {
    	if(singleton ==null){
    		singleton = new Singleton(); 
    	}
        return singleton;
    }
1.2.3、双重检测-懒汉式单例模式(解决线程安全和实现懒加载)
  1. 代码实现
	class Singleton02{
    /*第一步私有化构造器
     * */
    private Singleton02(){

    }

    private  static volatile Singleton02 singleton ;

    /*双重检测单例模式(推荐使用)
     * */
    public static  Singleton02 getSingleton() {
        if (singleton==null){
            synchronized (Singleton02.class){
                if (singleton==null){
                    singleton = new Singleton02();
                }
            }
        }
        return singleton;
    }
}
  1. 优缺点
    在这里插入图片描述
  2. volatile和synchronized的区别
    volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
    volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
    volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
    volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

2、工厂模式

2.1、简单工厂

原理:简单工厂模式可以理解为当为一个抽象的商品添加,一个具体的商品的时候,避免了大量的代码修改。
比如:
现有这些类,原始的披萨(抽象的商品),奶酪披萨(具体的商品),芝士披萨(具体商品)
原始的披萨:有公共的方法,A()、B()
奶酪披萨:[ 特有的方法,C()]、A()、B()
芝士披萨:[ 特有的方法,D()]、A()、B()

有一些生产商品production类需要区生产这些商品,比如production1、production2、production3
这些工厂会根据自己的需求去生产不太种类的披萨

	Production1(type){
	if(type=='奶酪')
	new 奶酪披萨()
	}else if(type=='芝士'){
	new 芝士披萨()
	}
	Production2(type){
	if(type=='奶酪')
	new 奶酪披萨()
	}else if(type=='芝士'){
	new 芝士披萨()
	}
	Production3(type){
	if(type=='奶酪')
	new 奶酪披萨()
	}else if(type=='芝士'){
	new 芝士披萨()
	}

当我们添加一个具体的披萨种类时,比如胡椒披萨,
这个时候我们需要修改去修改每一个工厂的实现(去添加一个else if)当工厂很多的时候,就需要修改很多代码

这个时候就可以用到我们的简单工厂的设计思想,通过一个factory工厂来,生产指定的披萨,这样只需要修改 factory类就能实现所有生产类production

在这里插入图片描述

在这里插入图片描述

3、代理模式

在这里插入图片描述

3.1、静态代理

目标对象(被代理对象)和代理对象都需要实现接口,这个接口就是需要代理的业务功能。

package design_pattern.proxy_pattern_static;

/**
 * <h3>
 *     这个是需要代理的方法(因为需要代理的方法,代理者和被代理者都可以完成)
 * </h3>
 *<p>
 *     比如:去买火车票,李华可以自己去买,当自己没空时可以找人(代理者)去买
 *</p>
 * @author 15594
 *
 */
public interface NeedProxyMethod {
    /**
     * 买火车票
     * @return 返回购票信息
     * @param name
     *          购票者的姓名
     * */
    String buyTrainTickets(String name);

}

package design_pattern.proxy_pattern_static;

/**
 * <h3>
 *     被代理买票的人
 * </h3>
 * <p>
 *     被代理买票的人除了可以买票以外,还可以做其他事情
 *     比如:吃饭、睡觉
 * </p>
 *
 * @author 15594
 *
 */
public class NeedProxyPeople implements NeedProxyMethod {

    /**被代理者的姓名*/
    private String name;

    public NeedProxyPeople() {
    }

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

    @Override
    public String buyTrainTickets(String name) {
        System.out.println(name+"需要买票");
        return "发布代购,等待代理人处理";
    }

    /**
     * 被代理的人除了可以去买票以外还可以去做其他事情
     * */
    public void eat(){
        System.out.println("干饭");
    }



}

package design_pattern.proxy_pattern_static;

/**
 * <p>
 *     代理购票的人
 * </p>
 * @author 15594
 */
public class ProxyPeople implements NeedProxyMethod {

    /**代理购票的人的名字*/
    private String name;

    public ProxyPeople() {

    }

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

    @Override
    public String buyTrainTickets(String name) {
        System.out.println(name+":代理买票");
        System.out.println("代购人不仅仅只能去买票,只要完成了购票功能,中途可以干其他事情。");
        return "代理买票成功";
    }

    /**
     * 代理人除了可以去买票以外还可以去做其他事情
     * */
    public void eat(){
        System.out.println("干饭");
    }
}

package design_pattern.proxy_pattern_static;

/**
 * 测试代码
 * @author 15594
 */
public class ProxyDemo {
    public static void main(String[] args) {
        NeedProxyMethod proxy = new ProxyPeople("小胖");

        proxy.buyTrainTickets("帮小明买票");

    }
}

3.2、动态代理

  • jdk动态代理
package design_pattern.proxy_pattern_moving;

/**
 *
 * 目标对象(被代理的对象)需要实现的接口
 *
 * @author 15594
 */
public interface IUserDao {
    /**
     * 根据用户id查询用户名
     * @return 返回根据id查询到的用户名
     * @param id
     * 用户id
     * */
    String queryUserNameById(int id);

    /**
     * 根据id修改用户名
     * @param id
     * 用户id
     * @param userName
     * 用户名
     * */
    void updateUserNameById(String userName,int id);

}

package design_pattern.proxy_pattern_moving;

/**
 * <h3>
 *    动态代理
 * </h3>
 * 目标对象(被代理的对象)实现类
 *
 * <h4>
 *     注意:动态代理(被代理者)的目标对象必须实现接口,代理对象不需要实现接口
 * </h4>
 *
 * @author 15594
 */
public class UserDaoImpl implements IUserDao {
    @Override
    public String queryUserNameById(int id) {
        System.out.println("根据"+id+"查询到李华");
        return "李华";
    }

    @Override
    public void updateUserNameById(String userName, int id) {
        System.out.println("已经将id为:"+id+"的用户名修改为:"+userName);
    }
}

package design_pattern.proxy_pattern_moving;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 *
 * 动态代理工厂类
 *
 * 创建动态代理对象(返回代理对象)
 * 动态代理不需要实现接口,但是需要指定接口类型
 * @author 15594
 */
public class ProxyFactory {

    /**通过构造器获取目标对象*/
    private Object target;

    /**
     * 传入一个目标对象
     * @param target 目标对象
     * */
    public ProxyFactory(Object target) {
        this.target = target;
    }
    /**
     * 给目标对象生成代理对象
     *
     * @return 返回代理对象
     * */
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  //其中args[]时目标对象调用方法时的参数
                System.out.println("开始事务2");
                //执行目标对象的方法
                Object invoke = method.invoke(target, args);
                System.out.println("提交事务2");
                System.out.println(method.getName());
                System.out.println("传进的参数个数:"+args.length);
                System.out.println("返回返回值:"+invoke);
                return invoke; //这个就是目标对象调用方法后的返回值
            }
        });
    }

}

package design_pattern.proxy_pattern_moving;

/**
 * 测试类
 * @author 15594
 */
public class Demo {
    public static void main(String[] args) {
        IUserDao userDao = new UserDaoImpl();
        ProxyFactory proxyFactory = new ProxyFactory(userDao);
        IUserDao proxyInstance = (IUserDao)proxyFactory.getProxyInstance();

        System.out.println(proxyInstance.queryUserNameById(1));
        proxyInstance.updateUserNameById("小明",1);
    }
}

  • cglib动态代理

参考:Java的三种代理模式

参考:设计模式之代理模式(三种)

4、适配器模式

  • 使用场景:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。也就是说当两个类已经实现好了,想让两个不相关的类产生一些联系(此时又不想重构代码),那么这个时候就可以使用适配器模式。

适配器模式详细解释

4.1、类适配器

package design_pattern.adapter.class_adapter;

/**
 * 类适配器模式
 * 适配者——需要适配的一个东西,比如电脑没有网线接口只有usb接口,需要一个转接器才能接上网线。其中电脑就是适配者
 * @author 15594
 */
public class Adaptee {
    /**
     * 用笔记本上网,但是这个笔记本没有网线接口,只有usb接口
     * */
    void goOnline(){
        System.out.println("成功上网");
    }
}
package design_pattern.adapter.class_adapter;

/**
 * 目标接口——比如电脑没有网线接口,只有usb接口,需要一个转接器才能接上网线。其中网线接口就是目标接口
 * @author 15594
 */
public interface Target {
    /**
     * 目标接口,这里代表网线接口,因为没有网线接口的电脑的目的是需要一个网线接口来连接网络,进行上网。
     * */
    void targetInterface();
}

类适配器的核心代码

package design_pattern.adapter.class_adapter;

/**
 *
 * 适配器——比如:电脑没有网线接口,只有usb接口,需要一个转接器才能接上网线。其中转接器就是适配器
 * @author 15594
 */
public class Adapter extends Adaptee implements Target {

    @Override
    public void targetInterface() {  //这里调用目标接口,但是却调用了其他的方法
        System.out.println("通过转接器连接上了网线。");
        goOnline();
    }
}
package design_pattern.adapter.class_adapter;

/**
 * 测试类
 * @author 15594
 */
public class Test {
    public static void main(String[] args) {
        Target target = new Adapter();
        /**
         * 注意:在实际生产中,目标接口(Target)和、适配者(Adaptee)一般都是已经实现好了的。
         * 我们正在需要编写的是Adapter(适配器)
         * */
        target.targetInterface();
    }

}

4.2、对象适配器

package design_pattern.adapter.class_adapter;

/**
 * 对象适配器模式
 * 适配者——需要适配的一个东西,比如电脑没有网线接口只有usb接口,需要一个转接器才能接上网线。其中电脑就是适配者
 * @author 15594
 */
public class Adaptee {
    /**
     * 用笔记本上网,但是这个笔记本没有网线接口,只有usb接口
     * */
    void goOnline(){
        System.out.println("成功上网");
    }
}
package design_pattern.adapter.class_adapter;

/**
 * 目标接口——比如电脑没有网线接口,只有usb接口,需要一个转接器才能接上网线。其中网线接口就是目标接口
 * @author 15594
 */
public interface Target {
    /**
     * 目标接口,这里代表网线接口,因为没有网线接口的电脑的目的是需要一个网线接口来连接网络,进行上网。
     * */
    void targetInterface();
}

类适配器的核心代码

package design_pattern.adapter.class_adapter;

/**
 *
 * 适配器——比如:电脑没有网线接口,只有usb接口,需要一个转接器才能接上网线。其中转接器就是适配器
 * @author 15594
 */
public class Adapter  implements Target {

    private Adaptee adaptee;

    @Override
    public void targetInterface() {
        System.out.println("通过转接器连接上了网线。");
        adaptee  = new Adaptee();
        adaptee.goOnline();
    }
}

package design_pattern.adapter.class_adapter;

/**
 * 测试类
 * @author 15594
 */
public class Test {
    public static void main(String[] args) {
        Target target = new Adapter();
        /**
         * 注意:在实际生产中,目标接口(Target)和、适配者(Adaptee)一般都是已经实现好了的。
         * 我们正在需要编写的是Adapter(适配器)
         * */
        target.targetInterface();
    }

}

5、工厂模式

工厂模式的初衷是屏蔽复杂对象的构建过程,想要获取一个工厂提供的对象只需要调用一个方法(create____();)就能获取到。工厂模式分为两种,一种是简单工厂,一种是抽象工厂。简单工厂模式(也叫工厂模式,模式只它),只能创建对应类的对象,也就是说我们需要获取class A 类的对象通过简单工厂模式只能得到,A类的对象。抽象工厂模式,如名字一样是抽象的,不确定的,一般抽象工厂模式会结合接口使用,抽象工厂会返回一个接口类型的对象,也就是实现了这个接口的类的对象,都能通过抽象工厂模式获取到。

5.1、简单工厂模式

获取一种固定类的对象。

package design_pattern.factory.simple_factory;

/**
 * 抽象产品
 *
 *
 * 颜色的抽象接口
 * @author 15594
 */
public interface Colour {
    /**打印颜色*/
    void getColour();
}

package design_pattern.factory.simple_factory;

import javax.naming.Name;

/**
 * 具体产品
 *
 *
 * 红色对象
 * @author 15594
 */
public class Red implements Colour {
    private String RGB;
    private String name;

    public void getRed() {
        System.out.println("红色");
    }

    @Override
    public void getColour() {
        System.out.println("红色");
    }
}

package design_pattern.factory.simple_factory;

/**
 * 具体产品
 *
 * 黄色对象
 * @author 15594
 */
public class Yellow implements Colour {
    private String RGB;
    private String name;

    public void getRed() {
        System.out.println("黄色");
    }

    @Override
    public void getColour() {
        System.out.println("黄色");
    }
}

package design_pattern.factory.simple_factory;

/**
 * 生产颜色对象的工厂
 * @author 15594
 */
public class ColourFactory {

    /**
     * @return 返回抽象的产品
     * @param name 根据输入的颜色类型名字返回向上转型的颜色对象
     * */
    public static Colour getColour(String name){
        switch (name){
            case "red":
                return new Red();
            case "yellow":
                return new Yellow();
            default:
                throw new RuntimeException("没有这个颜色");
        }
    }

}

package design_pattern.factory.simple_factory;

/**
 * 测试类
 * @author 15594
 */
public class Test {
    public static void main(String[] args) {

        Colour colour = ColourFactory.getColour("red");
        colour.getColour();
        ColourFactory.getColour("yellow").getColour();
        ColourFactory.getColour("yellow1").getColour();
        
    }
}

5.2、抽象工厂模式

获取实现了同一个接口的类的对象。

package design_pattern.factory.abstract_factory;

/**
 * 抽象产品——书
 *
 * @author 15594
 */
public interface Book {
    /**
     * 打印具体书的名字
     * */
    void getBookName();

    /**
     * 打印书的价格
     * */
    void getBookPrice();
}
package design_pattern.factory.abstract_factory;


/**
 * 具体产品——英语书
 *
 * @author 15594
 */
public class EnglishBook implements Book  {
    @Override
    public void getBookName() {
        System.out.println("英语书");
    }

    @Override
    public void getBookPrice() {
        System.out.println("价格:60");
    }
}

package design_pattern.factory.abstract_factory;

/**
 * 具体商品——音乐书
 *
 * @author 15594
 */
public class MusicBook implements Book {
    @Override
    public void getBookName() {
        System.out.println("音乐书");
    }

    @Override
    public void getBookPrice() {
        System.out.println("价格:30");
    }
}

package design_pattern.factory.abstract_factory;

/**
 * 抽象产品
 *
 *
 * 颜色的抽象接口
 * @author 15594
 */
public interface Colour {
    /**打印颜色*/
    void getColour();
}

package design_pattern.factory.abstract_factory;

/**
 * 具体产品
 *
 *
 * 红色对象
 * @author 15594
 */
public class Red implements Colour {
    private String RGB;
    private String name;

    public void getRed() {
        System.out.println("红色");
    }

    @Override
    public void getColour() {
        System.out.println("红色");
    }
}

package design_pattern.factory.abstract_factory;

/**
 * 具体产品
 *
 * 黄色对象
 * @author 15594
 */
public class Yellow implements Colour {
    private String RGB;
    private String name;

    public void getRed() {
        System.out.println("黄色");
    }

    @Override
    public void getColour() {
        System.out.println("黄色");
    }
}

package design_pattern.factory.abstract_factory;

/**
 * 抽象工厂——提供了生产具体商品的抽象方法,里面包含了所有工厂生产具体商品对象的方法
 *
 * @author 15594
 */
public abstract class AbstractFactory {
    /**
     * 获取颜色对象
     * @return 返回具体的商品对象
     * @param colour 指定生产的具体商品的名字
     * */
    public abstract Colour getColour(String colour);

    /**
     * 获取书本对象
     * @return 返回具体的商品对象
     * @param book 指定生产的具体商品的名字
     * */
    public abstract Book getBook(String book);
}

package design_pattern.factory.abstract_factory;

import design_pattern.factory.simple_factory.Red;
import design_pattern.factory.simple_factory.Yellow;

/**
 * 具体工厂类——用于生产具体商品
 *
 * @author 15594
 */
public class BookFactory extends AbstractFactory {


    @Override
    public Colour getColour(String colour) {
        return null;
    }

    @Override
    public Book getBook(String book) {
        switch (book){
            case "English":
                return new EnglishBook();
            case "Music":
                return new MusicBook();
            default:
                throw new RuntimeException("没有这本书");
        }
    }
}

package design_pattern.factory.abstract_factory;

public class ColourFactory extends AbstractFactory {
    @Override
    public Colour getColour(String colour) {
        switch (colour){
            case "red":
                return new Red();
            case "yellow":
                return new Yellow();
            default:
                throw new RuntimeException("没有这个颜色");
        }
    }

    @Override
    public Book getBook(String book) {
        return null;
    }
}

package design_pattern.factory.abstract_factory;

/**
 * 用于生产指定的工厂
 *
 * @author 15594
 */
public class FactoryBuilder {
    public static AbstractFactory getFactory(String factoryName){
        switch (factoryName){
            case "color":
                return new ColourFactory();
            case "book":
                return new BookFactory();
            default:
                throw new RuntimeException("没有这个工厂");
        }
    }
}

package design_pattern.factory.abstract_factory;

/**
 * 这是一个测试类
 *
 * @author 15594
 */
public class Test {
    public static void main(String[] args) {
        AbstractFactory colorFactory = FactoryBuilder.getFactory("color");
        Colour red = colorFactory.getColour("red");
        red.getColour();
        AbstractFactory bookFactory = FactoryBuilder.getFactory("book");
        Book english = bookFactory.getBook("English");
        english.getBookName();
        english.getBookPrice();
    }
}

6、建造者(Builder)模式

6.1、 建造者模式的介绍

建造者(Builder)模式的定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

注意:建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,
而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。

模式的结构, 建造者(Builder)模式的主要角色如下:

  • 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件(需要建造的复杂对象)。
  • 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。(将通用的方法抽象出来,一个抽象类
  • 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。(负责建造组件对象,继承抽象建造者
  • 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。(指定创建复杂对象的过程、流程

6.2、deom

  • 需要建造的复杂对象
/**
 * @author hs
 * @date 2021/10/21 13:43
 * 产品(需要建造的复杂对象)。以建造自行车对象为例:
 */
public class Product {
    /**自行车的id*/
    private int id;
    /** 轮子:一般来说,这是一个对象(轮子的大小、材料、id等)。这里为了方便就使用字符串来表示*/
    private String wheel;
    /** 车架*/
    private String frame;

    public Product() {
    }

    public Product(int id, String wheel, String frame) {
        this.id = id;
        this.wheel = wheel;
        this.frame = frame;
    }

    public int getId() {
        return id;
    }

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

    public String getWheel() {
        return wheel;
    }

    public void setWheel(String wheel) {
        this.wheel = wheel;
    }

    public String getFrame() {
        return frame;
    }

    public void setFrame(String frame) {
        this.frame = frame;
    }

    public void play(){
        System.out.println("骑自行车!");
    }
}

  • 抽象建造者
/**
 * @author hs
 * @date 2021/10/21 13:57
 * 抽象建造者。
 */
public abstract class Builder {
    /**创建产品对象*/
    protected Product product = new Product();
    /**建造轮子*/
    public abstract void buildWheel();
    /**建造车架*/
    public abstract void buildFrame();


    /**返回产品对象*/
    public Product getResult() {
        return product;
    }
}
  • 具体建造者
/**
 * @author hs
 * @date 2021/10/21 15:48
 * 具体的建造者
 */
public class ConcreteBuilder extends Builder {

    @Override
    public void buildWheel() {
        System.out.println("轮子创建流程:创建了一个轮子。");
        product.setWheel("轮子");
    }

    @Override
    public void buildFrame() {
        System.out.println("车架创建流程,创建了一个车架。");
        product.setFrame("车架");
    }

}

  • 指挥者:指挥自行车建造的整个过程
/**
 * @author hs
 * @date 2021/10/21 15:58
 * 指挥者,指挥自行车创建。比如先创建轮子,再创建车架。
 */
public class Director {
    private Builder builder;
    public Director(Builder builder) {
        this.builder = builder;
    }
    /**产品构建与组装方法*/
    public Product construct() {
        //先创建轮子
        builder.buildWheel();
        //再创建车架
        builder.buildFrame();
        //返回一辆建造好的自行车
        return builder.getResult();
    }
}
  • 测试建造者模式
/**
 * @author hs
 * @date 2021/10/21 16:06
 * 测试建造者模式
 */
public class Test {
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        Product construct = director.construct();
        construct.play();
    }
}

7、观察者模式(发布者-订阅者模式)

【例1】利用观察者模式设计一个程序,分析“人民币汇率”的升值或贬值对进口公司进口产品成本或出口公司的出口产品收入以及公司利润率的影响。

分析:当“人民币汇率”升值时,进口公司的进口产品成本降低且利润率提升,出口公司的出口产品收入降低且利润率降低;当“人民币汇率”贬值时,进口公司的进口产品成本提升且利润率降低,出口公司的出口产品收入提升且利润率提升。

这里的汇率(Rate)类是抽象目标类,它包含了保存观察者(Company)的 List 和增加/删除观察者的方法,以及有关汇率改变的抽象方法 change(int number);而人民币汇率(RMBrate)类是具体目标, 它实现了父类的 change(int number) 方法,即当人民币汇率发生改变时通过相关公司;公司(Company)类是抽象观察者,它定义了一个有关汇率反应的抽象方法 response(int number);进口公司(ImportCompany)类和出口公司(ExportCompany)类是具体观察者类,它们实现了父类的 response(int number) 方法,即当它们接收到汇率发生改变的通知时作为相应的反应。

package net.biancheng.c.observer;

import java.util.*;

public class RMBrateTest {
    public static void main(String[] args) {
        Rate rate = new RMBrate();
        Company watcher1 = new ImportCompany();
        Company watcher2 = new ExportCompany();
        rate.add(watcher1);
        rate.add(watcher2);
        rate.change(10);
        rate.change(-9);
    }
}

//抽象目标:汇率
abstract class Rate {
    protected List<Company> companys = new ArrayList<Company>();

    //增加观察者方法
    public void add(Company company) {
        companys.add(company);
    }

    //删除观察者方法
    public void remove(Company company) {
        companys.remove(company);
    }

    public abstract void change(int number);
}

//具体目标:人民币汇率
class RMBrate extends Rate {
    public void change(int number) {
        for (Company obs : companys) {
            ((Company) obs).response(number);
        }
    }
}

//抽象观察者:公司
interface Company {
    void response(int number);
}

//具体观察者1:进口公司
class ImportCompany implements Company {
    public void response(int number) {
        if (number > 0) {
            System.out.println("人民币汇率升值" + number + "个基点,降低了进口产品成本,提升了进口公司利润率。");
        } else if (number < 0) {
            System.out.println("人民币汇率贬值" + (-number) + "个基点,提升了进口产品成本,降低了进口公司利润率。");
        }
    }
}

//具体观察者2:出口公司
class ExportCompany implements Company {
    public void response(int number) {
        if (number > 0) {
            System.out.println("人民币汇率升值" + number + "个基点,降低了出口产品收入,降低了出口公司的销售利润率。");
        } else if (number < 0) {
            System.out.println("人民币汇率贬值" + (-number) + "个基点,提升了出口产品收入,提升了出口公司的销售利润率。");
        }
    }
}

观察者模式原理很简单发布者(被观察者)维护了一个订阅者(观察者)的列表。发布者可以往这个列表中增加、删除订阅者。当发布者发生变化(或者产生动作)时,发布者会去遍历订阅者列表,告诉订阅我产生了变化,让订阅者做出变化。

8、外观模式(门面模式)

8.1、什么是外观模式

  1. 菜鸟教程解释:
    门面模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟门面类交互就可以了。
    更好的划分访问层次: 通过合理使用Facade,可以帮助我们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。
  2. 我自己的理解
    屏蔽子系统(子模块、一个复杂难以理解的类)的内部实现,不直接让用户(程序员、api调用者)与子系统直接接触,而是创建一个外部的类(门面、外观类)然后提供一些简单容易理解的方法给用户调用(比如:子系统中的一个方法是实现一个如何穿越到古代的方法,一般用户很难理解这个方法是如何实现的吧,也不知道调用时需要传入什么样的参数,那么我们就创建一个简单的方法叫做穿越,传入的参数是人。简单方法直接调用具体穿越的方法,就能实现穿越,进而我们用户通过调用简单方法也能实现穿越,这样用户就很容易理解,我想穿越只需要把我自己传入到方法中即可。),这样就能降低系统的复杂性。

8.2、例子

例子是直接引用菜鸟教程的:门面模式
一些子模块

public class ModuleA {
    /**
     * 提供给子系统外部使用的方法
     */
    public void a1(){};
    
    /**
     * 子系统内部模块之间相互调用时使用的方法
     */
    private void a2(){};
    private void a3(){};
}
public class ModuleB {
    /**
     * 提供给子系统外部使用的方法
     */
    public void b1(){};
    
    /**
     * 子系统内部模块之间相互调用时使用的方法
     */
    private void b2(){};
    private void b3(){};
}
public class ModuleC {
    /**
     * 提供给子系统外部使用的方法
     */
    public void c1(){};
    
    /**
     * 子系统内部模块之间相互调用时使用的方法
     */
    private void c2(){};
    private void c3(){};
}

门面类:

public class ModuleFacade {
    
    ModuleA a = new ModuleA();
    ModuleB b = new ModuleB();
    ModuleC c = new ModuleC();
    /**
     * 下面这些是A、B、C模块对子系统外部提供的方法
     */
    public void a1(){
        a.a1();
    }
    public void b1(){
        b.b1();
    }
    public void c1(){
        c.c1();
    }
}

这样定义一个ModuleFacade类可以有效地屏蔽内部的细节,免得客户端去调用Module类时,发现一些不需要它知道的方法。比如a2()和a3()方法就不需要让客户端知道,否则既暴露了内部的细节,又让客户端迷惑。对客户端来说,他可能还要去思考a2()、a3()方法用来干什么呢?其实a2()和a3()方法是内部模块之间交互的,原本就不是对子系统外部的,所以干脆就不要让客户端知道。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值