Java常用设计模式
可参考:http://blog.youkuaiyun.com/zhangerqing/article/details/8194653/
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式6大原则:
参考:http://www.uml.org.cn/sjms/201211023.asp
- 单一职责原则
- 里氏替换原则
- 依赖倒置原则
- 接口隔离原则
- 迪米特原则
- 开闭原则
一、观察者模式
定义——当对象间存在一对多关系时,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并自动更新。
以下情况建议使用:
- 当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化
- 如果在更改一个对象的时候,需要同时连带改变其他对象,而且不知道究竟有多少对象需要被连带改变
1、自己实现观察者
/**
*目标对象,它知道观察它的观察者,并提供注册和删除观察者的接口
*/
public class Subject {
//保存注册观察者对象
private List<Observer> observers=new ArrayList<Observer>();
public void attach(Observer observer){
observers.add(observer);
}
public void detach(Observer observer){
observers.remove(observer);
}
//通知所有注册的观察者对象
protected void notifyObservers(){
for(Observer observer: observers){
observer.update(this);
}
}
}
/*
* 具体目标对象,负责把有关状态存入到相应的观察者对象中
*/
public class ConcreteSubject extends Subject{
//目标对象状态
private String subjectState;
public String getSubjectState(){
return subjectState;
}
public void setSubjectState(String subjectState){
this.subjectState=subjectState;
this.notifyObservers();
}
}
/**
*观察者接口
*/
public interface Observer {
public void update(Subject subiect);
}
/*
* 具体观察者对象,实现更新的方法,使自身状态和目标的状态保持一致
*/
public class ConcreteObserver implements Observer{
private String observerState;
//获取目标类的状态同步到观察者的状态中
@Override
public void update(Subject subiect) {
observerState=((ConcreteSubject)subiect).getSubjectState();
System.out.println(observerState);
}
}
public class Client {
public static void main(String[] args) {
ConcreteSubject subject=new ConcreteSubject();
Observer ob1=new ConcreteObserver();
Observer ob2=new ConcreteObserver();
subject.attach(ob1);
subject.attach(ob2);
subject.setSubjectState("将该内容通知到所有观察者");
}
}
2、利用JDK的Observer接口、Observable类实现观察者
/*
* 具体目标对象,负责把有关状态存入到相应的观察者对象中
*/
public class ConcreteSubject extends Observable{
//目标对象状态
private String subjectState;
public String getSubjectState(){
return subjectState;
}
public void setSubjectState(String subjectState){
this.subjectState=subjectState;
this.setChanged();//通知前规定加上该句
this.notifyObservers(subjectState);
}
}
/*
* 聚体观察者对象,实现更新的方法,使自身状态和目标的状态保持一致
*/
public class ConcreteObserver implements Observer{
private String observerState;
public String getObserverState() {
return observerState;
}
public void setObserverState(String observerState) {
this.observerState = observerState;
}
//获取目标类的状态同步到观察者的状态中
@Override
public void update(Observable arg0, Object arg1) {
System.out.println(arg1);
}
}
public class Client {
public static void main(String[] args) {
ConcreteSubject subject=new ConcreteSubject();
ConcreteObserver ob1=new ConcreteObserver();
ConcreteObserver ob2=new ConcreteObserver();
subject.addObserver(ob1);
subject.addObserver(ob2);
subject.setSubjectState("将该内容通知到所有观察者");
}
}
二、责任链模式
定义——将接收者对象连成一条链,并在该链上传递请求,直到有一个接收者对象处理它。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
发出请求的客户端并不知道链上哪个接收者处理该请求,从而实现了客户端和接收者的解耦。缺点是消耗较多的内存,每个请求都需要遍历所有接收者,直到找到为止,而可能有些接收者不经常用。
以下情况使用了责任链:
- java异常的抛出
- js的事件模型,捕获冒泡
- web过滤链
/*
* 价格处理人,负责处理客户折扣申请
*/
public abstract class PriceHandler {
//另一个接收者引用,用于传递请求
protected PriceHandler successor;
public void setSuccessor(PriceHandler successor) {
this.successor = successor;
}
//处理折扣申请
public abstract void processDiscount(float discount);
}
/*
* 销售,可以批准5%以内的折扣
*/
public class Sales extends PriceHandler {
@Override
public void processDiscount(float discount) {
if(discount<=0.05)
System.out.format("%s批准了折扣:%.2f%n", this.getClass().getName(),discount);
else
successor.processDiscount(discount);
}
}
/*
* 经理,可以批准10%以内的折扣
*/
public class Manager extends PriceHandler {
@Override
public void processDiscount(float discount) {
if(discount<=0.1)
System.out.format("%s批准了折扣:%.2f%n", this.getClass().getName(),discount);
else
successor.processDiscount(discount);
}
}
/*
* CEO,可以批准20%以内的折扣
*/
public class CEO extends PriceHandler{
@Override
public void processDiscount(float discount) {
if(discount<=0.2)
System.out.format("%s批准了折扣:%.2f%n", this.getClass().getName(),discount);
else
System.out.format("%s拒绝了折扣:%.2f%n", this.getClass().getName(),discount);
}
}
public class PriceHandlerFactory {
//创建PriceHandler的工厂方法
public static PriceHandler createPriceHandler(){
PriceHandler sales=new Sales();
PriceHandler manager= new Manager();
PriceHandler ceo= new CEO();
sales.setSuccessor(manager);
manager.setSuccessor(ceo);
return sales;
}
}
/*
* 客户,请求折扣
*/
public class Customer {
private PriceHandler handler;
public void setHandler(PriceHandler handler) {
this.handler = handler;
}
public void requestDiscount(float discount){
handler.processDiscount(discount);
}
public static void main(String[] args) {
Customer customer=new Customer();
customer.setHandler(PriceHandlerFactory.createPriceHandler());
customer.requestDiscount(0.2f);
}
}
三、代理模式
定义——为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外的服务。
1、以继承方式实现静态代理
public interface Moveable {
public void move();
}
public class Car implements Moveable{
@Override
public void move() {
try {
Thread.sleep(1000);
System.out.println("汽车行驶中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CarProxy1 extends Car{
public void move(){
System.out.println("汽车开始行驶");
super.move();
System.out.println("汽车结束行驶");
}
}
2、以聚合方式实现静态代理(相对于继承,推荐使用聚合)
public class CarTimeProxy implements Moveable{
private Moveable m;
public CarTimeProxy(Moveable m) {
this.m=m;
}
@Override
public void move() {
long s=System.currentTimeMillis();
System.out.println("汽车开始行驶");
m.move();
long e=System.currentTimeMillis();
System.out.println("汽车结束行驶...行驶了"+(e-s)+"ms");
}
}
public class CarTimeProxy implements Moveable{
private Moveable m;
public CarTimeProxy(Moveable m) {
this.m=m;
}
@Override
public void move() {
long s=System.currentTimeMillis();
System.out.println("汽车开始行驶");
m.move();
long e=System.currentTimeMillis();
System.out.println("汽车结束行驶...行驶了"+(e-s)+"ms");
}
}
public class Client {
public static void main(String[] args) {
Car car=new Car();
/*CarTimeProxy ctp=new CarTimeProxy(car);
CarLogProxy clp=new CarLogProxy(ctp);
clp.move();//先记录日志再记录时间*/
CarLogProxy clp=new CarLogProxy(car);
CarTimeProxy ctp=new CarTimeProxy(clp);
ctp.move();//先记录时间再记录日志
}
}
3、jdk动态代理
动态代理实现步骤:
- 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
- 创建被代理的类以及接口
- 调用Proxy的静态方法,创建一个代理类Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
- 通过代理调用方法
public class TimeHandler implements InvocationHandler{
private Object target;
public TimeHandler(Object target) {
this.target=target;
}
//proxy:被代理对象、method:被代理对象的方法、args:方法参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long s=System.currentTimeMillis();
System.out.println("汽车开始行驶");
method.invoke(target);
long e=System.currentTimeMillis();
System.out.println("汽车结束行驶...行驶了"+(e-s)+"ms");
return null;
}
}
public class Client {
public static void main(String[] args) {
Car car=new Car();
InvocationHandler h=new TimeHandler(car);
Class<?> cls=car.getClass();
/*
* loader:类加载器
* interfaces:实现接口
* h InvocationHandler
*/
Moveable m=(Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);
m.move();
}
}
四、工厂模式
工厂模式是最常用的实例化对象模式,是用工厂方法代替new操作的一种模式。
作用:如果有多处需要生成A的对象,那么你需要写很多A a=new A(),需要修改时,就会很麻烦!但是如果用工厂模式,只需要修改工厂代码。
作用:如果有多处需要生成A的对象,那么你需要写很多A a=new A(),需要修改时,就会很麻烦!但是如果用工厂模式,只需要修改工厂代码。
工厂模式应用实例:
- JDBC:用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它有一组Java语言编写的类和接口组成。用户可通过工厂模式来选择是mysql还是oracle
- Spring Beanfactory:作为Spring基础的IoC容器,是Spring的一个Bean工厂。
public interface Shape {
void draw();
}
public class Rectangle implements Shape {
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square implements Shape {
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
//type.properties文件
Square=factory.test.Square
Rectangle=factory.test.Rectangle
/*
* properties文件读取工具
*/
public class PropertiesReader {
public Map<String,String> getProperties(){
Properties props=new Properties();
Map<String,String> map=new HashMap<>();
try{
InputStream in=getClass().getResourceAsStream("type.properties");
props.load(in);
Enumeration en=props.propertyNames();
while(en.hasMoreElements()){
String key=(String)en.nextElement();
String property=props.getProperty(key);
map.put(key, property);
}
}catch (Exception e) {
e.printStackTrace();
}
return map;
}
}
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType == null)
return null;
if(shapeType.equalsIgnoreCase("RECTANGLE"))
return new Rectangle();
else if(shapeType.equalsIgnoreCase("SQUARE"))
return new Square();
return null;
}
//根据类名获取对象
public Shape getShapeByClass(String className){
try {
Map<String,String> map=new PropertiesReader().getProperties();
Shape shape = (Shape) Class.forName(map.get(className)).newInstance();//也可直接传进factory.test.Square
return shape;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
public class Client {
public static void main(String[] args) {
ShapeFactory f=new ShapeFactory();
Shape shape =f.getShapeByClass("Square");
shape.draw();
}
}
五、策略模式(组合方式)
定义——策略模式将可变的部分从程序中抽象分离成算法接口,在该接口下分别封装一系列算法实现,并使他们可以互相替换,从而导致客户端程序独立于算法的改变。
public interface FlyingStragety {
public void performFly();
}
public class FlyWithWin implements FlyingStragety{
@Override
public void performFly() {
System.out.println("飞起来了");
}
}
public class FlyNoWay implements FlyingStragety{
@Override
public void performFly() {
System.out.println("我不会飞");
}
}
public abstract class Duck {
private FlyingStragety flyingStragety;
public void quack(){
System.out.println("嘎嘎嘎");
}
public abstract void display();
public void setFlyingStragety(FlyingStragety flyingStragety) {
this.flyingStragety = flyingStragety;
}
public void fly(){
flyingStragety.performFly();
}
}
public class RedheadDuck extends Duck{
public RedheadDuck() {
super.setFlyingStragety(new FlyWithWin());
}
@Override
public void display() {
System.out.println("我的头是红色的");
}
}
/*
* 玩具鸭
*/
public class RubberDuck extends Duck{
public RubberDuck() {
super.setFlyingStragety(new FlyNoWay());
}
@Override
public void display() {
System.out.println("全身黄,嘴巴红!");
}
//重写该方法
public void quack(){
System.out.println("嘎~嘎~嘎~");
}
}
public class Test {
public static void main(String[] args) {
Duck duck1=new RedheadDuck();
duck1.display();//我的头是红色的
duck1.quack();//嘎嘎嘎
duck1.fly();//飞起来了
Duck duck=new RubberDuck();
duck.display();//全身黄,嘴巴红!
duck.quack();//嘎~嘎~嘎~
duck.fly();//我不会飞
}
}
六、适配器模式
定义——将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
//三相插座
public interface ThreePlugIf {
public void powerWithThree();
}
/*
* 二相转三相插座适配器
*/
public class TwoPlugAdapter implements ThreePlugIf{
private GBTwoPlug plug;
public TwoPlugAdapter(GBTwoPlug plug) {
this.plug=plug;
}
@Override
public void powerWithThree() {
System.out.println("通过转化");
plug.powerWithTwo();
}
}
public class GBTwoPlug {
//使用二相电流供电
public void powerWithTwo(){
System.out.println("使用二相电流供电");
}
}
public class NoteBook {
private ThreePlugIf plug;
public NoteBook(ThreePlugIf plug) {
this.plug=plug;
}
public void change(){
plug.powerWithThree();
}
public static void main(String[] args) {
GBTwoPlug two=new GBTwoPlug();
ThreePlugIf three=new TwoPlugAdapter(two);
NoteBook nb=new NoteBook(three);
nb.change();
}
}
七、单例模式
- 饿汉式单例
public class Singleton { private Singleton(){} //将构造函数私有化,不允许外部类直接创建对象 private static Singleton instance=new Singleton(); public static Singleton getInstance(){ return instance; } }
- 懒汉式单例(线程安全模式)
public class Singleton { private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ synchronized (Singleton.class) { if(instance == null) instance = new Singleton(); } } return instance; } }
- Initialization on Demand Holder模式(使用内部类,线程安全模式)
public class Singleton{ private Singleton(){} private static class SingletonHolder{ public final static Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.instance; } }
八、模板模式
定义——定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
public abstract class RefreshBeverage {
/*
* 封装了所有子类共同遵循的算法框架
*/
public final void prepareBeverageTemplate(){
boilWater();
brew();
pourInCup();
addCondiments();
}
private void boilWater() {
System.out.println("将水煮沸");
}
private void pourInCup() {
System.out.println("将饮料倒入杯中");
}
protected abstract void brew();
protected abstract void addCondiments();
}
public class Coffee extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("加入糖和牛奶");
}
}
public class Tea extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("用80度的热水浸泡茶叶5分钟");
}
@Override
protected void addCondiments() {
System.out.println("加入柠檬");
}
}