十大设计模式总结版

十大设计模式总结版

  • 十大设计模式
  • 1.Singleton 单例模式
    • 1.1单例模式的实现思路
      • 1.2饿汉类
        • 1.2.1优点
      • 1.3懒汉类
        • 1.3.1优点
      • 1.4双重检查锁
        • 1.4.1优点
      • 1.5静态内部类
        • 1.5.1优点
      • 1.6枚举类
        • 1.6.1优点
      • 1.7ThreadLocal
        • 1.7.1优点
  • 2.Proxy 代理模式
    • 2.1静态代理
      • 2.1.1静态代理的实现思路
      • 2.1.2优点
    • 2.2动态代理
      • 2.2.1动态代理的实现思路
    • 2.3Cglib代理
      • 2.3.1Cglib代理的实现思路
        • Cglib的maven依赖
      • 2.3.2优点
  • 3.Adapter适配器模式
    • 3.1类的适配器模式的实现思路(继承实现)
    • 3.2对象的适配器模式(扩展实现)
    • 3.3优点
  • 4.Chain责任链模式
    • 4.1责任链的实现思路
    • 4.2优点
  • 5.Simple Factory简单工厂模式
    • 5.1简单工厂的实现思路
  • 6.Factory Method工厂方法模式
    • 6.1工厂方法的实现思路
    • 6.2优点
  • 7.Template Method模板方法模式
    • 7.1模板方法的实现思路
    • 7.2优点
  • 8.Decorator 装饰器模式
    • 8.1装饰器的实现思路
    • 8.2优点
  • 9.Observer 观察者模式
    • 9.1观察者的实现思路
    • 9.2优点
  • 10.Strategy 策略模式
    • 10.1策略模式的实现思路
    • 10.2优点

十大设计模式

主要是对前面的设计模式进行一个总结,主要掌握以下十大设计模式,其他的设计模式后面的在慢慢熟悉。

1.Singleton 单例模式

1.1单例模式的实现思路

  1. 静态化实例对象,让实例对象与Class对象互相绑定,通过Class类对象就可以直接访问
  2. 私有化构造方法,禁止通过构造方法来创建多个实例
  3. 创建公共的静态方法,通过该静态方法来调用私有化构造方法来创建对象,并将其保存在一个静态成员变量中,用来返回该类的唯一实例。

1.2饿汉类

public class Hungry {
    //1.创建一个静态实例对象
    private static Hungry instance = new Hungry();

    //2. 私有化构造方法
    private Hungry() {}

    //3.在静态方法中创建实例对象,并将其返回
    public static Hungry getInstance() {
        return instance;        
    }
}
1.2.1优点
  • JVM层面的线程安全
  • 造成空间的浪费

1.3懒汉类

package com.technologystatck.designpattern.modereview.singleton;

public class Lazy {
    //1.创建一个静态实例对象,允许为空
    private static Lazy instance = null;

    //2.私有化构造方法
    private Lazy() {
    }

    //3.在静态方法中实例化对象,并将其返回
    public static Lazy getInstance() {
        if (instance == null) {
            instance = new Lazy();
        }
        return instance;
    }

    //4.若为线程安全可以使用synchronized关键字
    public static synchronized Lazy getSynInstance() {
        if (instance == null) {
            instance = new Lazy();
        }
        return instance;
    }
}
1.3.1优点
  • 节省空间,用到的时候再创建实例对象
  • 线程不安全
  • 若添加了synchronized关键字,对同步进行操作,有很严重的性能问题

1.4双重检查锁

package com.technologystatck.designpattern.modereview.singleton;

public class DoubleCheckLocking {
    //1.创建实例对象
    private static volatile DoubleCheckLocking instance=null;

    //2.私有化构造方法
    private DoubleCheckLocking(){

    }

    //3.使用静态方法中创建对象
    public static DoubleCheckLocking getInstance(){
        //先判断实例是否存在
        if(instance == null){
            //加锁创建实例
            synchronized (DoubleCheckLocking.class){
                //再次判断,若拿了锁很有可能出现还没来得及初始化就释放了锁
                //导致可能创建多个实例对象
                if(instance == null){
                    instance = new DoubleCheckLocking();
                }
            }
        }
        return instance;
    }
}
  • 使用volatile关键字修饰instance变量

    private static volatile DoubleCheckLocking instance=null;

1.4.1优点
  • 使用双重检查锁进行多层判断,保证了对象实例化
  • 使用volatile关键字禁止了JVM的指令重排序

1.5静态内部类

package com.technologystatck.designpattern.modereview.singleton;

public class StaticInner {
    //1.通过静态内部类实例化对象
    private static class StaticInnerSingleton{
        private static StaticInner instance = new StaticInner();
    }
    //2.私有化构造方法
    private StaticInner(){
        
    }
    //3.创建静态方法返回实例化的对象
    public static StaticInner getInstance(){
        return StaticInnerSingleton.instance;
    }
}

1.5.1优点
  • 没有加锁,线程安全
  • 即时用再加载,并发性能高

1.6枚举类

package com.technologystatck.designpattern.modereview.singleton;

enum Enums {

    //创建枚举类的实例
    INSTANCE;
    
    //对单例对象的进行相关操作的方法
    public void doSingleton(){
        System.out.println("正在执行枚举类实现的单例对象的方法");
    }
}
1.6.1优点
  • 不需要考虑序列化问题
  • 不需要考虑反射问题

1.7ThreadLocal

package com.technologystatck.designpattern.modereview.singleton;

public class ThreadLocals {
    //1.初始化ThreadLocal,同时实例化对象
    private static ThreadLocal threadInstance = new ThreadLocal();
    private static ThreadLocals instance=null;

    //2.使用静态方法将实例化的对象返回
    public static ThreadLocals getInstance(){
        if(threadInstance.get()==null){
            createInstance();
        }
        return instance;
    }

    //3.创建实例化对象的方法
    private static final void createInstance(){
        synchronized (ThreadLocals.class){
            if(instance==null){
                instance=new ThreadLocals();
            }
        }
        //设置非空值,以便后续判断不再执行创建操作
        threadInstance.set(threadInstance);
    }

    //4.调用remove方法清除当前线程的threadInstance变量的值
    public static void remove(){
        threadInstance.remove();
    }
}

1.7.1优点
  • 保证了线程安全
  • 即时用再初始化

2.Proxy 代理模式

2.1静态代理

2.1.1静态代理的实现思路

  • 静态代理需要先定义接口
  • 被代理对象与代理对象一起实现相同的接口
  • 通过调用相同的方法来调用目标对象的方法

  • 小明想要购买一套房子,他决定寻求一家房屋中介来帮助他找到一个面积超过100平方米的房子,只有符合条件的房子才会被传递给小明查看。

    package com.technologystatck.designpattern.modereview.proxy;
    
    public class StaticProxy {
        public static void main(String[] args) {
            House house1 = new House("武汉", 101);
            House house2 = new House("上海", 201);
            House house3 = new House("天津", 81);
            House house4 = new House("深圳", 88);
    
            HouseProxy houseProxy = new HouseProxy();
            houseProxy.tradeHouse(house1);
            houseProxy.tradeHouse(house2);
            houseProxy.tradeHouse(house3);
            houseProxy.tradeHouse(house4);
    
        }
    }
    
    //1.定义抽象接口
    //房屋交易接口
    interface HouseTransaction{
        //定义交易房子的方法
        void tradeHouse(House house);
    }
    //2.定义被代理对象
    class Seller implements HouseTransaction{
        @Override
        public void tradeHouse(House house) {
            System.out.println("我是卖家,我在"+house.getAddress()+"卖"+house.getArea()+"平房子");
        }
    }
    
    
    //3.定义代理对象
    //相当于房屋中介
    class HouseProxy implements HouseTransaction{
        @Override
        public void tradeHouse(House house) {
            if(house.getArea()>100){
                System.out.println("我是小明委托的中介,我在"+house.getAddress()+"看"+house.getArea()+"平房子");
            }
        }
    }
    
    //定义房子类
    class House{
        private String address;
        private int area;
    
        public House() {
        }
    
        public House(String address, int area) {
            this.address = address;
            this.area = area;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public int getArea() {
            return area;
        }
    
        public void setArea(int area) {
            this.area = area;
        }
    
        @Override
        public String toString() {
            return "House{" +
                    "address='" + address + '\'' +
                    ", area=" + area +
                    '}';
        }
    }
    

2.1.2优点

  • 静态代理在不改变目标对象的前提下,实现了对目标对象的功能扩展。

2.2动态代理

2.2.1动态代理的实现思路

  • 需要代理类实现接口,使用Proxy.newProxyInstance方法生成代理类
  • 实现InvocationHandler中的invoke方法,实现增强功能

  • ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的。
  • Class[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型。
  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入

  • 小明想要购买一套房子,他决定寻求一家房屋中介来帮助他找到一个面积超过100平方米的房子,只有符合条件的房子才会被传递给小明查看。买房还需要一些手续,他需要房屋中介来帮助他履行完这些手续。

    package com.technologystatck.designpattern.modereview.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    
    public class StaticProxy {
        public static void main(String[] args) {
            House house1 = new House("北京", 101);
            House house2 = new House("上海", 201);
            House house3 = new House("广州", 81);
            House house4 = new House("深圳", 88);
    
            ArrayList<House> houses = new ArrayList<>();
            houses.add(house1);
            houses.add(house2);
            houses.add(house3);
            houses.add(house4);
            HouseProxy houseProxy=null;
            for (House house : houses) {
                HouseTransaction target = new Seller();
                HouseTransaction proxy = (HouseTransaction) new HouseProxy(target).getProxy();
                if(house.getArea()>100){
                    proxy.tradeHouse(house);
                    proxy.serviceCharges(house);
                }
            }
    
        }
    }
    
    //1.定义抽象接口
    //房屋交易接口
    interface HouseTransaction{
        //定义交易房子的方法
        void tradeHouse(House house);
    
        void serviceCharges(House house);
    }
    //2.定义被代理对象
    class Seller implements HouseTransaction{
        @Override
        public void tradeHouse(House house) {
            System.out.println("有一个"+house.getAddress()+"的"+house.getArea()+"平房子");
        }
    
        @Override
        public void serviceCharges(House house) {
            System.out.println("可以交接"+house.getAddress()+"的"+house.getArea()+"平房子手续");
        }
    }
    
    
    //3.定义代理对象
    //相当于房屋中介
    class HouseProxy{
        private Object target;
    
        public HouseProxy(Object o) {
            this.target = o;
        }
    
        public Object getProxy(){
            return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
                //使用Proxy.newProxyInstance方法生成代理对象,
                //实现InvocationHandler中的 invoke方法,
                //在invoke方法中通过反射调用代理类的方法,并提供增强方法
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("House Proxy动态代理");
                    Object invoke = method.invoke(target, args);
    
                    return invoke;
                }
            });
        }
    }
    
    //定义房子类
    class House{
        private String address;
        private int area;
    
        public House() {
        }
    
        public House(String address, int area) {
            this.address = address;
            this.area = area;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public int getArea() {
            return area;
        }
    
        public void setArea(int area) {
            this.area = area;
        }
    
        @Override
        public String toString() {
            return "House{" +
                    "address='" + address + '\'' +
                    ", area=" + area +
                    '}';
        }
    }
    

优点:不需要实现接口,但是目标对象需要实现接口

2.3Cglib代理

2.3.1Cglib代理的实现思路

  • 通过enhancer来生成代理类,通过实现MethodInterceptor接口,并实现其中的intercept方法
  • 在该方法中可以添加增强方法,并利用反射Method或MethodProxy继承类来调用原方法
package com.technologystatck.designpattern.modereview.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class CglibProxy {
    public static void main(String[] args) {
        House house1 = new House("北京", 101);
        House house2 = new House("上海", 201);
        House house3 = new House("广州", 81);
        House house4 = new House("深圳", 88);

        ArrayList<House> houses = new ArrayList<>();
        houses.add(house1);
        houses.add(house2);
        houses.add(house3);
        houses.add(house4);
        for (House house : houses) {
            HouseTransaction proxyInstance = (HouseTransaction) new HouseProxy().getProxyInstance(Seller.class);
            if(house.getArea()>100){
                proxyInstance.tradeHouse(house);
                proxyInstance.serviceCharges(house);
            }
        }

    }
}

//1.定义抽象接口
//房屋交易接口
interface HouseTransaction{
    //定义交易房子的方法
    void tradeHouse(House house);

    void serviceCharges(House house);
}
//2.定义被代理对象
class Seller implements HouseTransaction{
    @Override
    public void tradeHouse(House house) {
        System.out.println("有一个"+house.getAddress()+"的"+house.getArea()+"平房子");
    }

    @Override
    public void serviceCharges(House house) {
        System.out.println("可以交接"+house.getAddress()+"的"+house.getArea()+"平房子手续");
    }
}


//3.定义代理对象
//相当于房屋中介
class HouseProxy implements MethodInterceptor {
    //给目标对象创建一个代理对象
    public Object getProxyInstance(Class c){
        //1.工具类
        Enhancer enhancer = new Enhancer();
        //2.设置父类
        enhancer.setSuperclass(c);
        //3.设置回调函数
        enhancer.setCallback(this);
        //4.创建子类(代理对象)
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理处理");
        Object object = methodProxy.invokeSuper(o, objects);
        return object;
    }
}

//定义房子类
class House{
    private String address;
    private int area;

    public House() {
    }

    public House(String address, int area) {
        this.address = address;
        this.area = area;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getArea() {
        return area;
    }

    public void setArea(int area) {
        this.area = area;
    }

    @Override
    public String toString() {
        return "House{" +
                "address='" + address + '\'' +
                ", area=" + area +
                '}';
    }
}




  • Cglib的maven依赖
<dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib</artifactId>
   <version>3.3.0</version>
</dependency>

2.3.2优点

  • 无需代理类实现接口

3.Adapter适配器模式

3.1类的适配器模式的实现思路(继承实现)

  • 定义期望获得的功能接口,完成扩展
  • 定义现有的接口,也就是需要被适配的接口
  • 定义现有接口的具体实现类,需要实现现有接口
  • 定义一个类适配器,通过继承现有接口来完成现有接口的扩展

小明购买了一台新电脑,该电脑使用 TypeC 接口,他已经有了一个USB接口的充电器和数据线,为了确保新电脑可以使用现有的USB接口充电器和数据线,他购买了一个TypeC到USB的扩展坞。使用适配器模式设计并实现这个扩展坞系统,确保小明的新电脑既可以通过扩展坞使用现有的USB接口充电线和数据线,也可以使用TypeC接口充电。

package com.technologystatck.designpattern.modereview.adapter;

public class ClassAdapter {
    public static void main(String[] args) {
        //实例化适配器,相当于就可以通过适配器完成两种接口充电
        AdapterCharge adapterCharge = new AdapterCharge();
        adapterCharge.chargeUseUSB();
        adapterCharge.chargeUseTypeC();
    }
}

//定义一个期望获得的功能接口
interface TypeCTarget{
    //使用TypeC接口充电
    void chargeUseTypeC();
}

//定义现有的USB接口
interface USBTarget{
    //使用USB接口充电
    void chargeUseUSB();
}

//现有的接口具体实现类,USB
class ConcreteUSBTarget implements USBTarget{

    @Override
    public void chargeUseUSB() {
        System.out.println("正在通过USB接口充电");
    }
}

//类适配器,相当于TypeC到USB充电的扩展坞
//继承现有接口来完成对现有接口的扩展
class AdapterCharge extends ConcreteUSBTarget implements TypeCTarget{
    //完成USB接口充电
    @Override
    public void chargeUseUSB() {
        super.chargeUseUSB();
    }

    //完成TypeC接口充电
    @Override
    public void chargeUseTypeC() {
        System.out.println("可以使用TypeC接口充电");
    }
}

3.2对象的适配器模式(扩展实现)

  • 定义期望获得的功能接口,完成扩展

  • 定义现有的接口,也就是需要被适配的接口

  • 定义现有接口的具体实现类,需要实现现有接口

  • 定义一个类适配器,通过继承现有接口,

    持有现有接口类一个实例,并完成其扩展功能,以此来实现目标接口

package com.technologystatck.designpattern.modereview.adapter;

public class ObjectAdapter {
    public static void main(String[] args) {
        USBTarget concreteUSBTarget = new ConcreteUSBTarget();
        AdapterCharge adapterCharge = new AdapterCharge(concreteUSBTarget);
        adapterCharge.chargeUseTypeC();
    }
}

//定义一个期望获得的功能接口--使用TypeC接口充电
interface TypeCTarget{
    //使用TypeC接口充电
    void chargeUseTypeC();
}

//定义现有的USB接口
interface USBTarget{
    //使用USB接口充电
    void chargeUseUSB();
}

//现有的接口具体实现类,USB
class ConcreteUSBTarget implements USBTarget{

    @Override
    public void chargeUseUSB() {
        System.out.println("正在通过USB接口充电");
    }
}

//类适配器,相当于TypeC到USB充电的扩展坞
//继承现有接口来完成对现有接口的扩展,持有实例完成扩展功能
class AdapterCharge implements TypeCTarget{

    private USBTarget usbTarget;

    public AdapterCharge() {
    }

    public AdapterCharge(USBTarget usbTarget) {
        this.usbTarget = usbTarget;
    }

    //在现有功能的基础上扩展功能
    @Override
    public void chargeUseTypeC() {
        usbTarget.chargeUseUSB();
        System.out.println("可以使用TypeC接口充电");
    }
}

3.3优点

  • 可以让任何两个没有关联的类一起运行
  • 提高了类的复用,将现有接口实现类进行隐藏

4.Chain责任链模式

4.1责任链的实现思路

  • 定义请求对象,含有很多属性,表示一个请求
  • 定义抽象处理者,主要用于处理请求,同时设置方法参数来保存其他的处理者
  • 定义具体处理者,实现抽象处理者接口,处理自己负责的请求,并且实例化抽象处理者,可以访问到下一个处理者,若能处理请求则在此处处理,若不能处理请求且处理者参数不为空则将请求发送给下一个处理者

小明所在的公司请假需要在OA系统上发布申请,整个请求流程包括多个处理者,每个处理者负责处理不同范围的请假天数,如果一个处理者不能处理请求,就会将请求传递给下一个处理者,请你实现责任链模式,可以根据请求天数找到对应的处理者。

审批责任链由主管(Supervisor), 经理(Manager)和董事(Director)组成,他们分别能够处理3天、7天和10天的请假天数。如果超过10天,则进行否决。

package com.technologystatck.designpattern.modereview.chainofresponsibility;


public class Chain {
    public static void main(String[] args) {
        Request requestObject1 = new Request("张三","病假",3);
        Request requestObject2 = new Request("李四","公假",6);
        Request requestObject3 = new Request("王五","事假",9);
        Request requestObject4 = new Request("赵六","事假",12);

        //定义责任链对象
        Supervisor supervisor = new Supervisor();
        Manager manager = new Manager(supervisor);
        Director director = new Director(manager);

        //执行
        supervisor.handlerRequest(requestObject1);
        manager.handlerRequest(requestObject2);
        director.handlerRequest(requestObject3);
        director.handlerRequest(requestObject4);

    }
}

//定义请求对象
class Request{
    //请求人
    String name;
    //请求事件
    String requestStr;
    //请求天数
    int day;

    public Request(String name, String requestStr, int day) {
        this.name = name;
        this.requestStr = requestStr;
        this.day = day;
    }

    public String getName() {
        return name;
    }

    public String getRequestStr() {
        return requestStr;
    }

    public int getDay() {
        return day;
    }


}

//定义抽象处理者
interface CurrentHandler{
    //设置处理当前请求的方法
    void handlerRequest(Request request);
}


//定义具体处理者-主管
class Supervisor implements CurrentHandler{

    //设置条件天数
    private static final int APPROVE_DAY=3;

    //设置下一个处理者
    private CurrentHandler nextHandler;

    public Supervisor() {
    }

    public Supervisor(CurrentHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    @Override
    public void handlerRequest(Request request) {
        if(request.getDay()<=APPROVE_DAY){
            System.out.println(request.getName()+" Approved by Supervisor.");
        }else if(nextHandler !=null){
            nextHandler.handlerRequest(request);
        }else{
            System.out.println(request.getName()+" No Approve by Supervisor.");
        }
    }
}
//定义具体处理者-主管
class Manager implements CurrentHandler{

    //设置条件天数
    private static final int APPROVE_DAY=7;

    //设置下一个处理者
    private CurrentHandler nextHandler;

    public Manager(CurrentHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    @Override
    public void handlerRequest(Request request) {
        if(request.getDay()<=APPROVE_DAY){
            System.out.println(request.getName()+" Approved by Manager.");
        }else if(nextHandler !=null){
            nextHandler.handlerRequest(request);
        }else{
            System.out.println(request.getName()+" No Approve by Manager.");
        }
    }
}
//定义具体处理者-董事
class Director implements CurrentHandler{

    //设置条件天数
    private static final int APPROVE_DAY=10;

    //设置下一个处理者
    private CurrentHandler nextHandler;

    public Director(CurrentHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    @Override
    public void handlerRequest(Request request) {
        if(request.getDay()<=APPROVE_DAY){
            System.out.println(request.getName()+" Approved by Director.");
        }else if(nextHandler !=null){
            nextHandler.handlerRequest(request);
        }else{
            System.out.println(request.getName()+" No Approve by Director.");
        }
    }
}

4.2优点

  • 将多个处理器组合在一起,依次处理请求
  • 添加新的处理器或者重新排列处理器非常容易

5.Simple Factory简单工厂模式

5.1简单工厂的实现思路

  • 定义简单工厂类,用于实现所有实例对象的内部逻辑,其中创建产品的方法可以被外界调用,创建所需的产品对象
  • 定义抽象产品类,是工厂类创建的所有对象的父类,封装了各种产品对象的公有放啊,
  • 定义具体产品类,每一个具体产品类都继承自抽象产品类,需要实现抽象产品类的方法

小明家有两个工厂,一个用于生产圆形积木,一个用于生产方形积木,请你帮他设计一个积木工厂系统,记录积木生产的信息。

package com.technologystatck.designpattern.modereview.simplefactory;


import java.util.ArrayList;
import java.util.List;

public class SimpleFactory {

    public static void main(String[] args) {

        BlockFactorySystem blockFactorySystem = new BlockFactorySystem();
        blockFactorySystem.BuildBlocks("redirect",2);
        blockFactorySystem.BuildBlocks("square",2);

        //创建圆形
        BlockFactory.factoryCreateBlock("redirect").createBlock();
        //创建方形
        BlockFactory.factoryCreateBlock("square").createBlock();

    }
}

//定义抽象产品类
abstract class Product{
    //创建积木方法
    abstract void createBlock();
}

//定义具体产品类--圆形积木
class RedirectBlock extends Product{

    @Override
    void createBlock() {
        System.out.println("创建圆形积木");
    }
}
//定义具体产品类--方形积木
class SquareBlock extends Product{

    @Override
    void createBlock() {
        System.out.println("创建方形积木");
    }
}

//定义工厂类
class BlockFactory{
    public static Product factoryCreateBlock(String type){
        if(type.equals("redirect")){
            return new RedirectBlock();
        }else if(type.equals("square")){
            return new SquareBlock();
        }else{
            throw new IllegalArgumentException("无效的积木");
        }
    }
}

//积木工厂系统
class BlockFactorySystem{
    //定义集合存放积木信息
    private List<Product> products=new ArrayList();

    //创建积木方法
    public void BuildBlocks(String type,int nums){
        for(int i=0;i<nums;i++){
            if(type.equals("redirect") || type.equals("square"))
            BlockFactory.factoryCreateBlock(type).createBlock();
        }
    }

}

6.Factory Method工厂方法模式

6.1工厂方法的实现思路

  • 定义抽象工厂接口,用于创建一族产品的方法,每个方法对应一种产品
  • 定义具体工厂类,实现抽象工厂接口,用于创建一组具体产品的对象
  • 定义抽象产品接口,为每种产品声明接口,在抽象产品接口中声明产品所有的业务方法
  • 定义具体产品类,定义了具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法

小明家有两个工厂,一个用于生产圆形积木,一个用于生产方形积木,请你帮他设计一个积木工厂系统,记录积木生产的信息。

package com.technologystatck.designpattern.modereview.factorymethod;


import java.util.ArrayList;
import java.util.List;

public class FactoryMethod {
    public static void main(String[] args) {
        new BlockFactorySystem().BuildBlocks(new RedirectBlockFactory(),3);
        new BlockFactorySystem().BuildBlocks(new SquareBlockFactory(),2);

        System.out.println("=====================");
        RedirectBlockFactory redirectBlockFactory = new RedirectBlockFactory();
        redirectBlockFactory.createBlock().createBlockProduct();
        BlockProduct block = new SquareBlockFactory().createBlock();
        block.createBlockProduct();
    }
}

//定义抽象产品接口
interface BlockProduct{
    void createBlockProduct();
}
//定义具体产品实现类-圆形积木
class RedirectBlock implements BlockProduct{

    @Override
    public void createBlockProduct() {
        System.out.println("创建圆形积木");
    }
}

//定义具体产品实现类-方形积木
class SquareBlock implements BlockProduct{

    @Override
    public void createBlockProduct() {
        System.out.println("创建方形积木");
    }
}


//定义抽象工厂接口
interface BlockFactory{
    //创建积木
    BlockProduct createBlock();
}

//定义具体工厂实现类-圆形积木
class RedirectBlockFactory implements BlockFactory{

    @Override
    public BlockProduct createBlock() {
        return new RedirectBlock();
    }
}

//定义具体工厂实现类-方形积木
class SquareBlockFactory implements BlockFactory{

    @Override
    public BlockProduct createBlock() {
        return new SquareBlock();
    }
}



//定义工厂系统
class BlockFactorySystem{
    private List<BlockProduct> blockProducts=new ArrayList<BlockProduct>();

    public void BuildBlocks(BlockFactory factory,int nums){
        for(int i=0;i<nums;i++){
            BlockProduct block = factory.createBlock();
            blockProducts.add(block);
            block.createBlockProduct();
        }
    }
}

6.2优点

  • 工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类
  • 每个具体工厂类只能创建一个具体产品类的实例

7.Template Method模板方法模式

7.1模板方法的实现思路

  • 定义一个抽象模板类,负责给出算法的轮廓和骨架,由一个模板方法和若干个基本方法构成

    • 定义模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法

    • 定义基本方法,是实现算法各个步骤的方法,是模板方法的组成部分

      • 抽象方法:由抽象类声明、由其具体子类实现

      • 具体方法:由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承

      • 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种

        用于判断的逻辑方法,方法名一般为isXxx,返回值类型为boolean类型

  • 可以定义多个具体模板类,实现抽象模板类中所定义的抽象方法和钩子方法,是顶级逻辑的组成步骤


小明喜欢品尝不同类型的咖啡,她发现每种咖啡的制作过程有一些相同的步骤,他决定设计一个简单的咖啡制作系统,使用模板方法模式定义咖啡的制作过程。系统支持两种咖啡类型:美式咖啡(American Coffee)和拿铁(Latte)。

咖啡制作过程包括以下步骤:

  1. 研磨咖啡豆 Grinding coffee beans
  2. 冲泡咖啡 Brewing coffee
  3. 添加调料 Adding condiments

其中,美式咖啡和拿铁的调料添加方式略有不同, 拿铁在添加调料时需要添加牛奶Adding milk

package com.technologystatck.designpattern.modereview.template;

public class Template {
    public static void main(String[] args) {
        CoffeeTemplate american = new American();
        CoffeeTemplate latte = new Latte();
        CoffeeTemplate milk = new Milk();

        //通过钩子方法进行判断
        if (!american.isMilk()) {
            american.makeCoffee();
        }
        if (!latte.isMilk()) {
            latte.makeCoffee();
        }
        if (!milk.isMilk())
            milk.makeMilk();
    }

}


abstract class CoffeeTemplate {
    //咖啡名称
    private String coffeeName;

    //构造函数

    public CoffeeTemplate(String coffeeName) {
        this.coffeeName = coffeeName;
    }

    //定义制造咖啡的模板方法
    final void makeCoffee() {
        System.out.println("making " + coffeeName + ": ");
        grindingCoffeeBeans();
        brewingCoffee();
        addingCondiments();
    }

    //定义制造牛奶的模板方法
    final void makeMilk() {
        System.out.println("making " + coffeeName + ": ");
        addingCondiments();
    }

    //定义实现模板方法的基本方法
    //研磨方法
    void grindingCoffeeBeans() {
        System.out.println("研磨咖啡豆");
    }

    //冲泡咖啡
    void brewingCoffee() {
        System.out.println("冲泡咖啡");
    }

    //添加调料根据咖啡的种类,调料不一样
    //定义基本方法中的抽象方法
    abstract void addingCondiments();

    //定义钩子方法,判断是否是牛奶,牛奶不需要添加其他
    boolean isMilk() {
        return false;
    }
}

//定义美式咖啡具体实现类
class American extends CoffeeTemplate {

    public American() {
        super("American Coffee");
    }

    @Override
    void addingCondiments() {
        System.out.println("添加American Coffee的调料");
    }
}

//定义拿铁咖啡具体实现类
class Latte extends CoffeeTemplate {
    public Latte() {
        super("Latte Coffee");
    }

    @Override
    void addingCondiments() {
        System.out.println("添加Latte Coffee的调料");
    }
}

//定义牛奶具体实现类,但是需要判断是否是牛奶
class Milk extends CoffeeTemplate {
    public Milk() {
        super("Milk");
    }

    @Override
    void addingCondiments() {
        System.out.println("牛奶不需要添加调料");
    }

    @Override
    boolean isMilk() {
        System.out.println("是牛奶,不需要添加调料");
        return true;
    }
}

7.2优点

  • 当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。
  • 当需要控制子类的扩展时,模板方法只在特定点调用钩子操作

8.Decorator 装饰器模式

8.1装饰器的实现思路

  • 定义抽象构件,通过抽象接口规范准备接收附加责任的对象
  • 定义具体构件,实现抽象构件,为装饰器添加一些职责
  • 定义抽象装饰,继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能
  • 定义具体装饰,实现抽象装饰的相关方法,并给出具体构件对象添加附加的功能

小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。

请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。

package com.technologystatck.designpattern.modereview.decorator;

public class Decorator {
    public static void main(String[] args) {
        CoffeeComponent latteCoffee = new LatteCoffee();
        CoffeeComponent blackCoffee = new BlackCoffee();

        latteCoffee.makeCoffee();
        blackCoffee.makeCoffee();

        System.out.println("====================");
        new Milk(latteCoffee).makeCoffee();
        new Sugar(blackCoffee).makeCoffee();

    }
}

//定义抽象构件
abstract class CoffeeComponent{

    //需要添加的调料名字
    private String seasoning;

    public CoffeeComponent() {
    }

    //可以自己手动传参
    public CoffeeComponent(String seasoning) {
        this.seasoning = seasoning;
    }

    public String getSeasoning() {
        return seasoning;
    }

    public void setSeasoning(String seasoning) {
        this.seasoning = seasoning;
    }

    //制作咖啡的方法
    abstract void makeCoffee();
}

//定义具体构件
//黑咖啡的制作
class BlackCoffee extends CoffeeComponent{
    public BlackCoffee() {
        super("黑咖啡浓缩原液");
    }

    @Override
    void makeCoffee() {
        System.out.println("making "+super.getSeasoning()+" black coffee");
    }
}

//拿铁的制作
class LatteCoffee extends CoffeeComponent{
    public LatteCoffee() {
        super("拿铁咖啡浓缩原液");
    }

    @Override
    void makeCoffee() {
        System.out.println("making "+super.getSeasoning()+" latte coffee");
    }
}

//定义抽象装饰
abstract class CoffeeDecorator extends CoffeeComponent{

    //实例化抽象构件
    private CoffeeComponent coffeeComponent;

    public CoffeeComponent getCoffeeComponent() {
        return coffeeComponent;
    }

    public void setCoffeeComponent(CoffeeComponent coffeeComponent) {
        this.coffeeComponent = coffeeComponent;
    }


    //默认构造方法
    public CoffeeDecorator(String seasoning, CoffeeComponent coffeeComponent) {
        super(seasoning);
        this.coffeeComponent = coffeeComponent;
    }
}


//定义具体装饰
//黑咖啡具体装饰类
class Milk extends CoffeeDecorator{
    
    public Milk(CoffeeComponent coffeeComponent) {
        //添加额外的操作
        //添加半杯奶
        super("半杯奶", coffeeComponent);
    }

    @Override
    void makeCoffee() {
        System.out.println("制作"+super.getSeasoning()+"的黑咖啡");
    }
}

class Sugar extends CoffeeDecorator{
    //添加额外的操作
    //添加两勺糖
    public Sugar( CoffeeComponent coffeeComponent) {
        super("两勺糖", coffeeComponent);
    }

    @Override
    void makeCoffee() {
        System.out.println("添加了"+super.getSeasoning()+"的拿铁");
    }
}

8.2优点

  • 在不影响其他对象的情况下,动态的给单个对象添加职责。
  • 声明目标对象时需要实现与目标类相同的业务接口
  • 可以在不修改目标类的前提下增强目标方法

9.Observer 观察者模式

9.1观察者的实现思路

  • 定义抽象主题,定义的接口中提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者对象的抽象方法
  • 定义具体主题,用于实现抽象主题中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象
  • 定义抽象观察者,定义的接口中包含了更新自己的抽象方法,当接到具体主题的更改通知时被调用
  • 定义具体观察者,实现抽象观察者中定义的抽象方法,当主题内部状态发生变化时,就通知到具体观察者并进行处理

小明所在的学校有一个时钟(主题),每到整点时,它就会通知所有的学生(观察者)当前的时间,请你使用观察者模式实现这个时钟通知系统。

注意点:时间从 0 开始,并每隔一个小时更新一次。

package com.technologystatck.designpattern.modereview.observer;

import java.util.ArrayList;
import java.util.List;

public class ClockObserver {
    public static void main(String[] args) {
        Clock clock = new Clock();
        ConcreteObserver concreteObserver1 = new ConcreteObserver("张三");
        ConcreteObserver concreteObserver2 = new ConcreteObserver("李四");
        ConcreteObserver concreteObserver3 = new ConcreteObserver("王五");

        //注册三个新用户
        clock.register(concreteObserver1);
        clock.register(concreteObserver2);
        clock.register(concreteObserver3);

        //通知方法通知所有的人
        clock.notifys("正在注册新用户");
        
        //提供注销用户
        clock.removes(concreteObserver2);
        //通知方法通知所有的人
        clock.notifys("正在注销用户"+concreteObserver2.getName());
        for(int i=0,updates=3;i<updates;i++){
            clock.tick();
        }
    }
}

//定义抽象主题
interface Subject{
    //增加订阅者
    void register(Observer observer);
    //删除订阅者
    void removes(Observer observer);
    //通知订阅者
    void notifys(String messages);
}
//定义具体主题
class Clock implements Subject{

    //存储所有的用户
    private List<Observer> observers=new ArrayList<>();
    private int hour=0;

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

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

    @Override
    public void notifys(String messages) {
        for (Observer observer : observers) {
            //调用更新方法通知全局
            observer.update(messages);
        }
    }

    //定义方法 模拟时钟
    public void tick(){
        hour=(hour+1)%24;
        //通知时间
        notifys("现在时间: "+hour);
    }
}

//定义抽象观察者
interface Observer{
    void update(String messages);
}

//定义具体观察者
class ConcreteObserver implements Observer{
    private String name;

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

    public String getName() {
        return name;
    }

    @Override
    public void update(String messages) {
        System.out.println(this.name+" --> "+messages);
    }
}

9.2优点

  • 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象
  • 类似广播机制,不需要具体收听者,只需分发广播

10.Strategy 策略模式

10.1策略模式的实现思路

  • 抽象策略类,定义一个公共接口,各种不同的算法以不同的方式实现接口,环境角色使用该接口调用不同的算法
  • 具体策略类,实现抽象策略定义的接口,并提供具体的算法实现
  • 环境类(上下文类),包含一个策略实例,并在需要时调用策略对象的方法

小明家的超市推出了不同的购物优惠策略,你可以根据自己的需求选择不同的优惠方式。其中,有两种主要的优惠策略:

  1. 九折优惠策略:原价的90%。
  2. 满减优惠策略:购物满一定金额时,可以享受相应的减免优惠。

具体的满减规则如下:

满100元减5元

满150元减15元

满200元减25元

满300元减40元

请你设计一个购物优惠系统,用户输入商品的原价和选择的优惠策略编号,系统输出计算后的价格。

package com.technologystatck.designpattern.modereview.strategy;

public class Strategy {
    public static void main(String[] args) {
        DiscountContext discountContext = new DiscountContext();

        DiscountStrategy9 discountStrategy9 = new DiscountStrategy9();
        DiscountStrategyFull discountStrategyFull = new DiscountStrategyFull();
//        discountContext.setStrategy(discountStrategy9);
        discountContext.setStrategy(discountStrategyFull);
        int price = discountContext.applyDiscount(120);
        System.out.println("折扣后的价格"+price);
    }
}

//定义抽象策略类
interface DiscountStrategy {
    //定义算法方法
    int applyDiscount(int originalPrice);
}

//定义具体策略类
//定义九折优惠策略类
class DiscountStrategy9 implements DiscountStrategy {
    @Override
    public int applyDiscount(int originalPrice) {
        return (int) (originalPrice * 0.9); //返回九折优惠后的价格(保留两位小数)
    }
}
//定义满减优惠策略类
class DiscountStrategyFull implements DiscountStrategy {
    //定义满足的价格
    private int[] thresholds={100,150,200,300};
    //定义满减的价格
    private int[] discounts={5,15,25,40};

    @Override
    public int applyDiscount(int originalPrice) {
        //先遍历满足的价格
        for(int i=thresholds.length-1;i>=0;i--){
            //若价格有大于或等于满足价格中
            //从最高的价格开始遍历,若有,则返回满减价格
            //例如,如果大于300,则因为从后开始遍历,所以满减的价格也是从后开始遍历,则是减去40
            if(originalPrice>=thresholds[i]){
                //返回满减价格
                return originalPrice-discounts[i];
            }

        }
        //若价格小于满足价格数组,则返回原价
        return originalPrice;
    }
}


//定义上下文类
class DiscountContext {
    private DiscountStrategy strategy;

    //设置方法
    public void setStrategy(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    //输入原价格
    //通过该类来调用折扣方法,进行价格折扣
    public int applyDiscount(int orignalPrice) {
        return strategy.applyDiscount(orignalPrice);
    }
}


10.2优点

  • 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中
  • 系统中各个算法独立,根据运行时动态选择具体要执行的行为

你可能感兴趣的:(笨蛋学设计模式,设计模式)