十大设计模式总结版
- 十大设计模式
- 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单例模式的实现思路
- 静态化实例对象,让实例对象与Class对象互相绑定,通过Class类对象就可以直接访问
- 私有化构造方法,禁止通过构造方法来创建多个实例
- 创建公共的静态方法,通过该静态方法来调用私有化构造方法来创建对象,并将其保存在一个静态成员变量中,用来返回该类的唯一实例。
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{@Overridepublic void tradeHouse(House house) {System.out.println("我是卖家,我在"+house.getAddress()+"卖"+house.getArea()+"平房子");} }//3.定义代理对象 //相当于房屋中介 class HouseProxy implements HouseTransaction{@Overridepublic 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;}@Overridepublic 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{@Overridepublic void tradeHouse(House house) {System.out.println("有一个"+house.getAddress()+"的"+house.getArea()+"平房子");}@Overridepublic 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方法中通过反射调用代理类的方法,并提供增强方法@Overridepublic 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;}@Overridepublic 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{@Overridepublic void tradeHouse(House house) {System.out.println("有一个"+house.getAddress()+"的"+house.getArea()+"平房子");}@Overridepublic 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();}@Overridepublic 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;}@Overridepublic String toString() {return "House{" +"address='" + address + '\'' +", area=" + area +'}';}
}
<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{@Overridepublic void chargeUseUSB() {System.out.println("正在通过USB接口充电");}
}//类适配器,相当于TypeC到USB充电的扩展坞
//继承现有接口来完成对现有接口的扩展
class AdapterCharge extends ConcreteUSBTarget implements TypeCTarget{//完成USB接口充电@Overridepublic void chargeUseUSB() {super.chargeUseUSB();}//完成TypeC接口充电@Overridepublic 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{@Overridepublic void chargeUseUSB() {System.out.println("正在通过USB接口充电");}
}//类适配器,相当于TypeC到USB充电的扩展坞
//继承现有接口来完成对现有接口的扩展,持有实例完成扩展功能
class AdapterCharge implements TypeCTarget{private USBTarget usbTarget;public AdapterCharge() {}public AdapterCharge(USBTarget usbTarget) {this.usbTarget = usbTarget;}//在现有功能的基础上扩展功能@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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{@Overridevoid createBlock() {System.out.println("创建圆形积木");}
}
//定义具体产品类--方形积木
class SquareBlock extends Product{@Overridevoid 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{@Overridepublic void createBlockProduct() {System.out.println("创建圆形积木");}
}//定义具体产品实现类-方形积木
class SquareBlock implements BlockProduct{@Overridepublic void createBlockProduct() {System.out.println("创建方形积木");}
}//定义抽象工厂接口
interface BlockFactory{//创建积木BlockProduct createBlock();
}//定义具体工厂实现类-圆形积木
class RedirectBlockFactory implements BlockFactory{@Overridepublic BlockProduct createBlock() {return new RedirectBlock();}
}//定义具体工厂实现类-方形积木
class SquareBlockFactory implements BlockFactory{@Overridepublic 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)。
咖啡制作过程包括以下步骤:
- 研磨咖啡豆 Grinding coffee beans
- 冲泡咖啡 Brewing coffee
- 添加调料 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");}@Overridevoid addingCondiments() {System.out.println("添加American Coffee的调料");}
}//定义拿铁咖啡具体实现类
class Latte extends CoffeeTemplate {public Latte() {super("Latte Coffee");}@Overridevoid addingCondiments() {System.out.println("添加Latte Coffee的调料");}
}//定义牛奶具体实现类,但是需要判断是否是牛奶
class Milk extends CoffeeTemplate {public Milk() {super("Milk");}@Overridevoid addingCondiments() {System.out.println("牛奶不需要添加调料");}@Overrideboolean 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("黑咖啡浓缩原液");}@Overridevoid makeCoffee() {System.out.println("making "+super.getSeasoning()+" black coffee");}
}//拿铁的制作
class LatteCoffee extends CoffeeComponent{public LatteCoffee() {super("拿铁咖啡浓缩原液");}@Overridevoid 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);}@Overridevoid makeCoffee() {System.out.println("制作"+super.getSeasoning()+"的黑咖啡");}
}class Sugar extends CoffeeDecorator{//添加额外的操作//添加两勺糖public Sugar( CoffeeComponent coffeeComponent) {super("两勺糖", coffeeComponent);}@Overridevoid 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;@Overridepublic void register(Observer observer) {observers.add(observer);}@Overridepublic void removes(Observer observer) {observers.remove(observer);}@Overridepublic 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;}@Overridepublic void update(String messages) {System.out.println(this.name+" --> "+messages);}
}
9.2优点
- 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象
- 类似广播机制,不需要具体收听者,只需分发广播
10.Strategy 策略模式
10.1策略模式的实现思路
- 抽象策略类,定义一个公共接口,各种不同的算法以不同的方式实现接口,环境角色使用该接口调用不同的算法
- 具体策略类,实现抽象策略定义的接口,并提供具体的算法实现
- 环境类(上下文类),包含一个策略实例,并在需要时调用策略对象的方法
小明家的超市推出了不同的购物优惠策略,你可以根据自己的需求选择不同的优惠方式。其中,有两种主要的优惠策略:
- 九折优惠策略:原价的90%。
- 满减优惠策略:购物满一定金额时,可以享受相应的减免优惠。
具体的满减规则如下:
满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 {@Overridepublic 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};@Overridepublic int applyDiscount(int originalPrice) {//先遍历满足的价格for(int i=thresholds.length-1;i>=0;i--){//若价格有大于或等于满足价格中//从最高的价格开始遍历,若有,则返回满减价格//例如,如果大于300,则因为从后开始遍历,所以满减的价格也是从后开始遍历,则是减去40if(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优点
- 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中
- 系统中各个算法独立,根据运行时动态选择具体要执行的行为