目录
什么是设计模式?
对于设计人员,特别是开发人员吗,往往受限于眼界或经验不能够体会到设计原则的实用性,或者在处理具体问题时,不知道如何把设计原则应用到到设计和代码,因此产生了“设计模式”。
随着参与的项目越来越多,人们发现:很多问题并不是一个项目中出现的,它会在很多的项目中出现。于是人们就把这些问题总结出来,然后给出了解决这些问题的方案,而这些方案同城为"设计模式"(解决问题的套路)。
设计模式的分类
经过漫长岁月沉淀,人们总结出23种设计模式,通分为三大类:
- 创建模式:创建一些特殊的对象,或者在特殊要求下创建对象
- 结构模式:主要利用组合/聚合或者继承,让类与类能够形成某种关联关系--代理
- 行为模式:刻画了类和对象交换及分配职责的方式
创建模式
作用:创建一些特殊的对象,或者特殊要求下创建对象
单例模式
是一种创建型的设计模式,涉及的是如何创建对象。单例模式的核心:无论使用该类方法多少次,都只产生一个该类对象,可以减少系统内存的消耗。
单例模式--饿汉模式
public class Singleton {
//当构造方法私有化后,无法在当前类的外部去通过构造方法产生对象
// 创建本类的私有构造方法
private Singleton(){}
private static Singleton singleton = new Singleton();
// 提供一个静态方法 返回当前的对象
public static Singleton getInstance(){
return singleton;
}
}
【注意】
类加载时,会直接实例化单例对象,以后都返回该对象的引用。
优点:没有加锁,执行效率高,线程安全的实例
缺点:类加载时,会直接实例化单例对象,不管我有没有使用到该单例对象,浪费内存
单例模式--懒汉模式
public static LazySingleton getInstance(){
if(singleton == null){// 判断对象是否被初始化
// 对象没有被初始化,则加上类锁
synchronized (LazySingleton.class){
// 同时只有一个线程能够到这里
if(singleton == null){
// 创建实例对象
singleton = new LazySingleton();
}
}
}
// 实例对象的引用
return singleton;
}
【注意】
双重检验 首先先判断实例是否为null,
为null则使用synchronized锁住类 ,
然后在同步块中,再一次判断实例是否为null,为null则初始化实例。
优点:线程安全,且效率高的) 把锁的粒度变小,只锁第一次初始化时。
单例模式--静态内部类
public class InnerSingleton {
private InnerSingleton(){}
// 静态内部类
private static class Inner{
private static InnerSingleton instance = new InnerSingleton();
}
public static InnerSingleton getInstance(){
return Inner.instance;
}
}
【注意】
通过静态内部类 完成单例模式的创建。
在外部类加载时,并不会加载内部类,也就是不会执行new 实例(),这属于懒加载。
只有第一次调用getInstance方法时,才会加载。
单例模式--枚举
public class EnumSingleton {
private EnumSingleton(){}
private static enum SinEnum{
// 自定义的枚举值
TEST;
private EnumSingleton es = new EnumSingleton();
}
public static EnumSingleton getInstance(){
SinEnum s = SinEnum.TEST;
return s.es;
}
}
【注意】
通过枚举创建 单例模式。
不常用
工厂模式
将使用者和对象的生产者进行分离。
在工厂模式中,几乎都有三种角色,工厂(抽象工厂、具体工厂) 产品(抽象产品、具体产品) 使用者。使用者想要使用产品,不用自己去生产产品,把生产的动作交给工厂去做,使用者只需要从工厂提供产品的位置(方法)去拿就好。
简单工厂模式--顾客需要给出清单
例:不同类拥有同一行为。
先定义一个产品接口,拥有共通的方法。
public interface Product {
public void play();
}
不同类型的产品实现该接口
public class Phone implements Product{
@Override
public void play() {
System.out.println("play phone");
}
}
不同类型的产品实现该接口
public class IPad implements Product{
@Override
public void play() {
System.out.println("play IPad");
}
}
创建一个工厂类
public class Factory {
public Product getProduct(String type){
if(type == null){
return null;
}
if(type.equals("Phone")){
System.out.println("生产 Phone");
return new Phone();
}else if(type.equals("IPad")){
System.out.println("生产 IPad");
return new IPad();
}
return null;
}
}
创建一个顾客测试类
public class Test {
public static void main(String[] args) {
Factory factory = new Factory();
// 需要一个手机,只需告知给工厂即可,不用管任何的细节,屏蔽了具体的实现
Product phone = factory.getProduct("Phone");
Product iPad = factory.getProduct("IPad");
phone.play();
iPad.play();
}
}
最后输出结果:
生产 Phone
Play Phone
生产IPad
Play IPad
工厂方法模式--根据工厂能产生什么顾客拿什么
工厂可以产生统一品牌的商品,会根据商品去抽象工厂,对每一个产品,提供一个工厂实现类。
先定义一个产品接口,拥有共通的方法。
public interface Product {
public void play();
}
创建工厂接口
public interface Factory {
/** 方法返回值 抽象产品 */
public Product create();
}
不同类型的产品实现该接口
public class Phone implements Product{
@Override
public void play() {
System.out.println("play phone");
}
}
同时创建该产品的生产工厂
public class PhoneFactory implements Factory{
@Override
public Product create() {
System.out.println("生产 Phone");
return new Phone();
}
}
不同类型的产品实现该接口
public class IPad implements Product{
@Override
public void play() {
System.out.println("IPad play");
}
}
同时创建该产品的生产工厂
public class IPadFactory implements Factory {
@Override
public Product create() {
System.out.println("生产 IPad");
return new IPad();
}
}
创建顾客测试类
public class Test {
public static void main(String[] args) {
Factory factory = new PhoneFactory();
Factory factory1 = new IPadFactory();
Product phone = factory.create();
Product iPad = factory1.create();
phone.play();
iPad.play();
}
}
输出结果:
生产 Phone
Play Phone
生产 IPad
IPad Play
抽象工厂模式
根据工厂能产生什么顾客拿什么,但是工厂能产生的产品会有多种品牌。
超级工厂,可以生产不同品牌的各种产品,抽象出超级工厂,也要抽象出产品,然后根据不同的品牌给出该品牌商品的工工厂实现类。
例:
提供一个创建一系列相关或相互依赖对象的接口, 而无需指定他们具体的类。-- 创建模式
代入场景:我们作为工厂老板,
工厂目前可以代工ApplePhone、AppleIPad,
拓展业务代工HuawePhone、HuaweiIPad---提供多个类去完成业务
如果我还需要继续扩展业务XiaomiPhone、XiaoMiIPad,需要提供的类就也多
所以为了工厂更好的发展,需要对工厂升级
1.对生产的产品进行细化,然后抽象
抽象产品---手机、平板
2.具体产品类
ApplePhone 和 AppleIPad
HuaweiPhone 和 HuaweiIPad
3.根据不同的品牌给出工厂(需要先对工厂进行抽象)
3.1抽象工厂两个gong--造手机和造平板
3.2 给出具体的Huawei工厂 和 Apple工厂
原型模式
根据一个已经存在的对象,利用克隆的方式,来创建一个和他一样的对象。
浅克隆-- 利用Object中clone()实现
1.让被克隆的类实现Cloneable接口
2.重写clone方法,方法访问修饰符public
3.对象.clone()的方式的到一个一样的对象
public class Man implements Cloneable, Serializable {
/** 姓名 */
private String name;
// 调用Object的clone方法 浅度克隆
public Man clone() throws CloneNotSupportedException {
Object obj = super.clone();
return (Man) obj;
}
}
深度克隆
1.克隆对象所涉及的自定义类,需要实现序列化接口
2.在需要克隆的类中,添加一个方法,完成序列化反序列化即可。
// 深度克隆的实现
public class Man implements Cloneable, Serializable {
/** 姓名 */
private String name;
public Man depthClone() throws IOException, ClassNotFoundException {
// 获取对象信息,把当前对象写入另一块内存
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(bo);
objOut.writeObject(this);
// 读取内存 创建对象
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream objIn = new ObjectInputStream(bi);
Object obj = objIn.readObject();
return (Man) obj;
}
}
【注意】
浅度克隆,可以克隆一样的对象,但是对象中属性,如果是引用类型,该属性会指向相同的引用。
深度克隆,使用对象序列化克隆一样的对象。 如果属性为引用类型,不会再重复引用,它会重写创建同类型的数据完成引用。
PS
对于设计模式而言,在使用过程中有几点需要大家注意:
1.模式用在什么地方
2.模式的名称---对模式的描述
3.模式的具体实现
4.模式使用后的优缺点,特别是当一个模式有多个方案时,要去了解这些多种方案的优缺点,才能够在合适使用选用合适的方案。