设计模式学习笔记--23种设计模式(一)

来源:互联网 发布:linux默认用户名密码 编辑:程序博客网 时间:2024/05/16 19:03

模式一:单例模式

(一) 介绍

定义:确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。
这里写图片描述

(二) 实践

优点

  • 减少内存开销,特别是一个对象需要频繁的创建和销毁时
  • 减少系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久贮存在内存中,这里要注意垃圾回收机制,特别是J2EE.
  • 避免对资源的多重利用
  • 可以设置全局的访问点,优化和共享资源

缺点

  • 没有接口,扩展很难
  • 对测试不利
  • 与单一职责有冲突

应用场景

  • 要求生成唯一序列号的环境
  • 在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,使用线程安全的单例模式保持计数器的值
  • 创建一个对象需要消耗过多的资源,比如访问I/O和数据库
  • 需要定义大量的静态常量和静态方法
  • Spring中,每个Bean默认的都是单例的
//同步且高效率的单例模式:class Single{    private static Single s= null;    private Single(){}    public static Single getInstance(){         if(s==null){             synchronized(Single.class){                 if(s==null)                  s=new Single();            }        }    }}

单例模式的扩展-有上线的多例模式

//旗舰店总共有宝马,奔驰两种车,有五个人从该旗舰店买车public class Car{     private static int maxNumOfCar = 2;    private static ArrayList<String> nameList= new ArrayList<String>();    private static ArrayList<Car> carList= new ArrayList<Car>();    private static int countNumOfCar=0;static{     for(int i=0;i<maxNumOfCar ;i++){         carList.add(new Car("车"+(i+1)));    }}private Car(){}private Car(String name){     nameList.add(name);}//旗舰店开始展出车public static Car getInstance(){     Random random= new Random();    countNumOfCar= random.nextInt(maxNumOfCar);    return carList.get(countNumOfCar);}public static void drive(){     System.out.println("开车兜风");}}//开始购买车public class people{     public static void main(String[] args){         int peopleNum= 10;        for(int i=0;i<peopleNum;i++){             //构建一个单例模式            Car car= Car.getInstance();            car.drive();        }    }}

模式二:工厂方法模式

(一) 介绍

定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
这里写图片描述
工厂模式通用图:

  • 抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义
  • Creator为抽象类创建类,也就是抽象工厂
  • 如何创建产品类是由具体实现的工厂ConcreteCreator完成的

下面给出工厂类通用模板接口设计:

//抽象产品类public abstract class Product{     //产品类的公共方法    public void method1(){         //业务逻辑处理    }    //抽象方法    public abstract void method2();}//具体的产品可以有多个,都继承于抽象产品类public class ConcreteProduct1 extends Product{     public void method2(){         //业务逻辑处理    }}public class ConcreteProduct2 extends Product{     public void method2(){         //业务逻辑处理    }}

抽象工厂类负责实现产品对象的产生

//抽象工厂类public abstract class Creator{     /*     * 创建一个产品对象,其输入参数类型可以自行设置     *通常为String,Enum,Class等,当然也可以为空     */public abstract <T extends Product> T createProduct(Class<T> c);}

具体如何产生一个产品的对象,是由具体的工厂类实现的

//具体工厂类public class ConcreteCreator extends Creator{     public <T extends Product> T createProduct(Class<T> c){         Product product = null;        try{             product=(Product)Class.forName(c.getName()).newInstance();        } catch (Exception e) {             //异常处理        }        return (T) product    }}

实际场景应用

public class Client{     public static void main(String[] args){         Creator creator = new ConcreteCreator();        Product product = creator.creatorProduct(ConcreteProduct1.class);        //继续业务处理    }}

(二) 应用

优点:

  • 良好的封装性,代码结构清晰,一个调用者需要一个具体的产品对象,只要知道这个产品的类名就可以了
  • 工厂方法模式的扩展性好
  • 屏蔽产品类。产品类的实例化是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定
  • 解耦框架

使用场景

  • 工厂类模式是new一个对象的替代品,需要慎重的考虑是否需要一个工厂类进行管理,增加了代码的复杂性
  • 需要灵活的、可扩展性的框架时,可以考虑采用工厂模式。比如网路测试中,需要测试不同的协议的流量,可以看成不同的产品,设计一个工厂类,根据传入的条件参数产生不同的产品(协议)
  • 可用于异构项目中
  • 可以使用在测试驱动开发的框架下

(三) 扩展

1、缩小为简单工厂模式

这里写图片描述

//定义人类public interface Human{     public void getColor();    public void talk();}//创建三个不同的人种public class BlackHuman implements Human{     public void getColor() {         //业务逻辑    }    public void talk(){         //业务逻辑    }}public class YellowHuman implements Human{     public void getColor() {         //业务逻辑    }    public void talk(){         //业务逻辑    }}public class WhiteHuman implements Human{     public void getColor() {         //业务逻辑    }    public void talk(){         //业务逻辑    }}

而工厂实现生产人类方法的输入参数应该是Human接口的实现类,所以应该为Class类型,采用泛型为createHuman的输入参数进行限制:必须是Class类型;必须是Huamn的实现类。

public abstract class AbstractHumanFactory{     public abstract <T extends Human> T createHuman(Class<T> c);}

然后就是HumanFactory的创建以及实例化

public class HumanFactory extends AbstractHumanFactory {     public <T extends Human> T createHuman(Class<T> c){         Human human= null;        try{             //产生一个人种            human=(T)Class.forName(c.getName()).newInstance();        }catch (Exception e){             //异常描述        }        return (T)human;    }}

最后就是Client的创建,进行生产人类

public class Client{     public static void main(String[] args){         AbstractHumanFactory factory = new HumanFactory();        Human whiteHuman= factory.createHuman(WhiteHuman.class);        whiteHuman.getColor();        whiteHuman.talk();        //创建实例化其它的两种人类        ...    }}

简化为下面的含有static参数的形式,在类图中去掉了AbstractHumanFactory 抽象类,同时把createHuman方法设置为静态类,简化了类的创建过程。
这里写图片描述
程序代码如下:

public class HumanFactory{     public static <T extends Human> T createHuman(Class<T> c){         //定义一个生产出的人种        Human human= null;                try{             //产生一个人种            human=(T)Class.forName(c.getName()).newInstance();        }catch (Exception e){             //异常描述        }        return (T)human;    }}//相应的Client也会发生改动public class Client{     public static void main(String[] args){         Human whiteHuman= HumanFactory.createHuman(WhiteHuman.class);        whiteHuman.getColor();        whiteHuman.talk();        //创建实例化其它的两种人类        ...    }}

2、升级为多个工厂类

这里写图片描述

3、替代单例模式

4、延迟初始化

一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用
这里写图片描述
ProductFactory负责产品类对象的创建工作,并且通过一个prMap变量产生一个缓存。

//延迟加载的工厂类public class ProductFactory{     private static final Map<String,Product> proMap = new HashMap();    public static synchronized Product createProduct(String type) throws Exception {         Product product = null;        //如果Map中已经有这个对象        if(proMap.containsKey(type)){             product= proMap.get(type);        }else{             if(type.equals("Product1")){                 product= new ConcreteProduct1();            }else{                 product= new ConcreteProduct2();            }            //同时把对象放到缓存容器中            proMap.put(type,product);        }        return product;    }}

模式三:抽象工厂模式

(一)介绍:

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类

通用类图:

这里写图片描述

通用源码图:

这里写图片描述

代码模板:

public abstract class AbstractProductA{     //每个产品共有的方法    public void shareMethod(){     }    //每个产品相同的方法,不同的实现    public abstract void doSomething();}

具体产品实现类:

//产品A1的实现类public class ProductA1 extends AbstractProductA{     public void doSomething(){         System.out.println("产品A1的实现方法");    }}//产品A2的实现类public class ProductA2 extends AbstractProductA{     public void doSomething(){         System.out.println("产品A2的实现方法");    }}//产品B1的实现类public class ProductB1 extends AbstractProductB{     public void doSomething(){         System.out.println("产品B1的实现方法");    }}//产品B2的实现类public class ProductB2 extends AbstractProductB{     public void doSomething(){         System.out.println("产品B2的实现方法");    }}

抽象工厂AbstractCreator的职责是定义每个工厂要实现的功能,在通用代码中,抽象工厂类实现了两个产品族的产品创建(如果有N个产品族,在抽象工厂类中就有N个创建方法)

public abstract class AbstractCreator {     //创建A产品家族    public abstract AbstractProductA createProductA();    //创建B产品家族    public abstract AbstractProductB createProductB();}

如何创建一个产品,就应该由具体的实现类来完成(有M个产品等级就应该有M个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务)

//产品等级1的实现类public class Creator1 extends AbstractCreator {     //只生产产品等级为1的A类产品    public AbstractProductA creatProductA(){         return new ProductA1();    }    //只生产产品等级为1的B类产品    public AbstractProductB creatProductB(){         return new ProductB1();    }}
//产品等级2的实现类public class Creator2 extends AbstractCreator {     //只生产产品等级为1的A类产品    public AbstractProductA creatProductA(){         return new ProductA2();    }    //只生产产品等级为1的B类产品    public AbstractProductB creatProductB(){         return new ProductB2();    }}

最后,在具体的业务中产生一个无关的对象

public class Client {     public static void main(Stirng[] args) {         //定义两个工厂        AbstractCreator creator1 = new Creator1();        AbstractCreator creator2 = new Creator2();        //产生分别具有两个等级的两个不同类型的对象        AbstractProductA a1= creator1.createProductA();        AbstractProductA a2= creator2.createProductA();        AbstractProductB b1= creator1.createProductB();        AbstractProductB b2= creator2.createProductB();        //实现业务逻辑        ..........    }}

(二)应用:

优点:

  1. 封装性
  2. 产品族的约束为非公开状态

缺点:

产品族扩展非常困难

使用场景:

一个对象族都有相同的约束关系

注意事项:

抽象工厂模式产品族(产品个数)扩展困难,而产品等级(产品属性)扩展容易,即横向扩展容易,纵向扩展难。

(未完待续…)

参考文献

《设计模式之禅》 秦小波著
《Java核心技术 卷I》 周立新等译
《算法分析与设计》 霍红卫译

0 0
原创粉丝点击