23种设计模式(Java)

所有内容来源于网络。

uml使用的关系符号参考 http://www.uml.org.cn/oobject/201510214.asp

极客学院给出了设计模式的学习文档 , https://wiki.jikexueyuan.com/project/java-design-pattern/

代码见 https://gitee.com/wuyicode/design-pattern

设计模式主要分三个类型

  • 创建型

  • 结构型

  • 行为型

 

首先谈谈策略模式

属于 行为类模式 ,把行为抽象成接口,再聚合到类里。

UML中的聚合与组合

UML的类图中一般包含五种关系即 关联 聚合 组合 泛化 依赖。

 

参考 https://blog.csdn.net/liushuijinger/article/details/6994265

简单地说, 组合是不可分割的,聚合就不是。聚合关系比组合关系的紧密型要差些。

聚合的关系明显没有组合紧密 。

大雁不会因为雁群解散而无法生存,而翅膀就无法脱离大雁而单独生存,所以组合关系的类具有相同的生命周期 。

 雁群

class GooseGroup    
{
    public Goose goose;
    public GooseGroup(Goose goose){
        this.goose = goose;
    }
}

 大雁

public class Goose
{
    public Wings wings;
    public Goose(){
        wings=new Wings();
    }
}

使用案例

 

interface IStrategy {
    public void doSomething();
}
class ConcreteStrategy1 implements IStrategy {
    public void doSomething() {
        System.out.println("具体策略1");
    }
}
class ConcreteStrategy2 implements IStrategy {
    public void doSomething() {
        System.out.println("具体策略2");
    }
}
class Context {
    private IStrategy strategy;

    public Context(IStrategy strategy){
        this.strategy = strategy;
    }

    public void execute(){
        strategy.doSomething();
    }
}

public class Client {
    public static void main(String[] args){
        Context context;
        System.out.println("-----执行策略1-----");
        context = new Context(new ConcreteStrategy1());
        context.execute();

        System.out.println("-----执行策略2-----");
        context = new Context(new ConcreteStrategy2());
        context.execute();
    }
}

 

观察者模式

一个对象要时刻监听着另一个对象,只要它的状态一发生改变,自己随之要做出相应的行动。

观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生变化时,这个方法就会被触发调用。

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}

@Data
public class WeatherData implements Subject {
    private float temperatrue;
    private float pressure;
    private float humidity;
    private ArrayList<Observer> observers;

    public WeatherData() {
        observers = new ArrayList<>();
    }

    //当数据有更新时,就调用 setData
    public void setData(float temperature, float pressure, float humidity) {
        this.temperatrue = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.clear();
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        if(observers.contains(o))
            observers.remove(o);
    }

    @Override
    public void notifyObservers() {
        observers.forEach( observer -> observer.update(temperatrue, pressure, humidity));
    }
}

调用示例。WeatherData 是被观察的对象。

public static void main(String[] args) {
    WeatherData weatherData = new WeatherData();
    weatherData.registerObserver(new CurrentConditions());
    weatherData.setData(10f, 40f, 50.55f);

    System.out.println("----------------------------");
    weatherData.registerObserver(new BaiduSite());
    weatherData.setData(20f, 40f, 50.55f);
}

给出具体的观察者

// 实际的观察者
public class CurrentConditions implements Observer {
    // 温度,气压,湿度
    private float temperature;
    private float pressure;
    private float humidity;
    @Override
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }
    public void display() {
        System.out.println("***Today mTemperature: " + temperature + "***");
        System.out.println("***Today mPressure: " + pressure + "***");
        System.out.println("***Today mHumidity: " + humidity + "***");
    }

}

public class BaiduSite implements Observer {
    private float temperature;
    private float pressure;
    private float humidity;
    @Override
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }
    public void display() {
        System.out.println("===百度网站====");
        System.out.println("***百度网站 气温 : " + temperature + "***");
        System.out.println("***百度网站 气压: " + pressure + "***");
        System.out.println("***百度网站 湿度: " + humidity + "***");
    }
}

 

装饰者

在软件设计中,对已有对象的功能进行扩展。 把通用功能封装在装饰器中,用到的地方进行调用。

体现开闭原则。

@Data
public abstract class Drink {
    public String des; // 描述
    private float price = 0.0f;
    public abstract float cost();   // 计算费用的抽象方法
}

public class Decorator extends Drink {
    Drink obj;
    public Decorator(Drink drink) {
        obj = drink;
    }
    @Override
    public float cost() {
        return super.getPrice() + obj.getPrice();
    }
    @Override
    public String getDes() {
        return des + " " + getPrice() + " && " + obj.getDes();
    }
}

 

public class Coffee extends Drink {
    @Override
    public float cost() {
        return 1;
    }
}
public class Chocolate extends Decorator {
    public Chocolate(Drink drink) {
        super(drink);
        setDes("巧克力");
        setPrice(3.1f);
    }
}
public class Milk extends Decorator {
    public Milk(Drink obj) {
        super(obj);
        setDes("牛奶");
        setPrice(2.0f); 
    }
}

调用示例

public static void main(String[] args) {
    Drink order = new Coffee();
    order = new Milk(order);
    order = new Chocolate(order);

    System.out.println("order 加入一份牛奶 加入一份巧克力  费用 =" + order.cost());
    System.out.println("order 加入一份牛奶 加入一份巧克力 描述 = " + order.getDes());
}

 

单例设计模式

特点是

  • 禁止通过new 来 创建对象

  • 构造函数 是 private

  • 给出 getInstance() 函数,来提供单例对象。

确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

最简单的 饿汉式单例

/**
 *  静态常量方法
 *  缺点是没有懒加载,有可能造成浪费。
 *  优点是,线程安全。
 */
public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return singleton;
    }
}

懒汉式单例

public class Singleton {
    private static Singleton singleton;
    private Singleton(){}
    // 加入同步处理的代码,解决线程安全问题。
    public static synchronized Singleton getInstance(){
        if(singleton==null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

懒汉式单例 的基础上做 双重检查 优化

class Singleton06 {
    // 构造函数私有化
    private Singleton06() {
    }
    // volatile保证线程的可见性, 效果更好。
    private static volatile Singleton06 instance;
    // 双重检查
    public static Singleton06 getInstance() {
        if (instance == null) {
            synchronized (Singleton06.class) {
                if (instance == null)
                    instance = new Singleton06();
            }
        }
        return instance;
    }
}

静态内部类的写法

class Singleton07 {
    // 构造函数私有化
    private Singleton07() {
    }
    /**
     * 静态内部类 实现了懒加载和线程安全。
     */
    private static class SingletonInstance {
        private static final Singleton07 INSTANCE = new Singleton07();
    }

    public static synchronized Singleton07 getInstance(){
        return SingletonInstance.INSTANCE;
    }

}

还有 利用枚举的写法

enum Singleton08{
    INSTANCE,
    ;
    public void sayOK() {
        System.out.println("ok~");
    }
}

 

工厂模式

简单工厂

简单工厂 不是 23种设计模式。这个方法不好,违反了 开闭原则。所以不提倡。

public class SimpleFactory {

    public static Pizza createPizza(String orderType) {
        Pizza pizza = null;
        System.out.println("使用简单工厂模式2");
        if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName(" 希腊披萨 ");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName(" 奶酪披萨 ");
        } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }
}

工厂方法

/**
 * 抽象类
 */
public abstract class Pizza {
    protected String name;

    /**
     * 抽象方法
     * 各个子类的不同之处就在这里
     */
    public abstract void prepare();

    public void bake(){}
    public void cut(){}
    public void box(){}

    public String getName() {
        return name;
    }

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

目的是 便于日后扩展其它类。这里给出的 Pizza() 类,规定了 方法,它的基类去实现这些方法即可。

抽象工厂

抽象工厂是在 工厂方法的基础上,再做一层抽象。可以理解为 工厂的工厂。

 

命令模式

命令模式的适用场景

对于大多数请求-响应模式的功能,比较适合使用命令模式,正如命令模式定义说的那样,命令模式对实现记录日志、撤销操作等功能比较方便。

 

  • Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令。

  • ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现。

  • Client类:最终的客户端调用类。

以上三个类的作用应该是比较好理解的,下面我们重点说一下Invoker类和Recevier类。

  • Invoker类:调用者,负责调用命令。

  • Receiver类:接收者,负责接收命令并且执行命令。

class Invoker {
    private Command command;
    public void setCommand(Command command) {
        this.command = command;
    }
    public void action(){
        this.command.execute();
    }
}

abstract class Command {
    public abstract void execute();
}

class ConcreteCommand extends Command {
    private Receiver receiver;
    public ConcreteCommand(Receiver receiver){
        this.receiver = receiver;
    }
    public void execute() {
        this.receiver.doSomething();
    }
}

class Receiver {
    public void doSomething(){
        System.out.println("接受者-业务逻辑处理");
    }
}

public class Client {
    public static void main(String[] args){
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(receiver);
        //客户端直接执行具体命令方式(此方式与类图相符)
        command.execute();

        //客户端通过调用者来执行命令
        Invoker invoker = new Invoker();
        invoker.setCommand(command);
        invoker.action();
    }
}

 

代理模式

静态代理,是把目标对象,通过接口来聚合 。

/**
 * 静态代理
 */
public class TeacherDaoProxy implements ITeacherDao {
    private ITeacherDao target; // 目标对象,通过接口来聚合

    public TeacherDaoProxy(ITeacherDao target) {
        this.target = target;
    }

    @Override
    public void teach() {
        target.teach();
    }
}

public class TeacherDao implements ITeacherDao {
    @Override
    public void teach() {
        System.out.println(" 老师授课中  。。。。。");
    }
}

public static void main(String[] args) {
    TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(new TeacherDao());
    teacherDaoProxy.teach();
}

动态代理

动态代理的代理类 是动态生成的。

可以分为

  • 基于接口的jdk动态代理

  • 基于类的 cglib实现

主要内容有 :Proxy 和 InvocationHandler。

先说 jdk动态代理,本质是,使用反射机制。

/**
 * 动态代理
 */
public class ProxyFactory {
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxyInstance(){
        ClassLoader loader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        Object proxyInstance = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("JDK代理开始~~");
                // 反射机制调用目标对象的方法
                Object invoke = method.invoke(target, args);
                return invoke;
            }
        });
        return proxyInstance;
    }
}

public class TeacherDao implements ITeacherDao {
    @Override
    public void teach() {
        System.out.println(" 老师授课中.... ");
    }

    @Override
    public void sayHello(String name) {
        System.out.println("hello " + name);
    }
}
public static void main(String[] args) {
    ITeacherDao instance = (ITeacherDao) new ProxyFactory(new TeacherDao()).getProxyInstance();
    // 两次调用方法, 也就意味着两次使用了invoke 反射。
    instance.teach();
    instance.sayHello("tom");
}

cglib实现方式,是增强的动态代理, 不需要实现接口。

添加maven依赖。

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2</version>
</dependency>
public class ProxyFactory implements MethodInterceptor {
    //维护一个目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    // 返回一个代理对象:  是 target 对象的代理对象
    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理模式 ~~ 开始");
        Object invoke = method.invoke(target, objects);
        System.out.println("Cglib代理模式 ~~ 提交");
        return invoke;
    }
}

public class TeacherDao {
    public String teach() {
        System.out.println(" 老师授课中  , 我是cglib代理,不需要实现接口 ");
        return "hello";
    }
}
public static void main(String[] args) {
    TeacherDao instance = (TeacherDao) new ProxyFactory(new TeacherDao()).getProxyInstance();
    String res = instance.teach();
    System.out.println(res);
}

 

 

 

posted on 2020-04-07 22:23  wuyicode  阅读(254)  评论(0编辑  收藏  举报