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

模式一:单例模式

(一) 介绍

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

(二) 实践

优点

  • 减少内存开销,特别是一个对象需要频繁的创建和销毁时
  • 减少系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久贮存在内存中,这里要注意垃圾回收机制,特别是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》 周立新等译
《算法分析与设计》 霍红卫译

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值