软件工程——设计模式之创建型模式(单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。)

目录

设计模式的六大原则

单例模式

抽象工厂模式

建造者模式

工厂模式

原型模式

设计模式的六大原则

  1. 开闭原则(Open Close Principle):开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
  2. 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对"开-闭"原则的补充。实现"开-闭"原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
  3. 依赖倒转原则(Dependence Inversion Principle:这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
  4. 接口隔离原则(Interface Segregation Principle):这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
  5. 迪米特法则(最少知道原则)(Demeter Principle):为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
  6. 合成复用原则(Composite Reuse Principle):原则是尽量使用合成/聚合的方式,而不是使用继承

创建型模式

单例模式

单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例

单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

java 复制代码
/**
 * Created by jingbin on 2016/10/27.
 * 1.单例模式的饿汉式[可用]
 * (1)私有化该类的构造函数
 * (2)通过new在本类中创建一个本类对象
 * (3)定义一个公有的方法,将在该类中所创建的对象返回
 * <p>
 * 优点:从它的实现中我们可以看到,这种方式的实现比较简单,在类加载的时候就完成了实例化,避免了线程的同步问题。
 * 缺点:由于在类加载的时候就实例化了,所以没有达到Lazy Loading(懒加载)的效果,也就是说可能我没有用到这个实例,但是它
 * 也会加载,会造成内存的浪费(但是这个浪费可以忽略,所以这种方式也是推荐使用的)。
 */

public class SingletonEHan {

    private SingletonEHan() {}

    /**
     * 1.单例模式的饿汉式[可用]
     */
    private static SingletonEHan singletonEHan = new SingletonEHan();

    public static SingletonEHan getInstance() {
        return singletonEHan;
    }

//     SingletonEHan instance= SingletonEHan.getInstance();

    /**
     * 2. 单例模式的饿汉式变换写法[可用]
     * 基本没区别
     */
    private static SingletonEHan singletonEHanTwo = null;

    static {
        singletonEHanTwo = new SingletonEHan();
    }

    public static SingletonEHan getSingletonEHan() {
        if (singletonEHanTwo == null) {
            singletonEHanTwo = new SingletonEHan();
        }
        return singletonEHanTwo;
    }
    //     SingletonEHan instance= SingletonEHan.getSingletonEHan();


}
java 复制代码
    private SingletonLanHan() {}
    private static SingletonLanHan singletonLanHanFour;
    public static SingletonLanHan getSingletonLanHanFour() {
   	    if (singletonLanHanFour == null) {
   		synchronized (SingletonLanHan.class) {
   		    if (singletonLanHanFour == null) {
   			singletonLanHanFour = new SingletonLanHan();
   		    }
   		}
   	    }
   	    return singletonLanHanFour;
   }
   
java 复制代码
/**
 * Created by jingbin on 2016/10/28.
 * 7. 内部类[推荐用]
 * <p>
 * 这种方式跟饿汉式方式采用的机制类似,但又有不同。
 * 两者都是采用了类装载的机制来保证初始化实例时只有一个线程。
 * 不同的地方:
 * 在饿汉式方式是只要Singleton类被装载就会实例化,
 * 内部类是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类
 * <p>
 * 优点:避免了线程不安全,延迟加载,效率高。
 */

public class SingletonIn {

    private SingletonIn() {
    }

    private static class SingletonInHodler {
        private static SingletonIn singletonIn = new SingletonIn();
    }

    public static SingletonIn getSingletonIn() {
        return SingletonInHodler.singletonIn;
    }
}
java 复制代码
/**
 * Created by jingbin on 2016/10/28.
 * 8. 枚举[极推荐使用]
 *
 * 这里SingletonEnum.instance
 * 这里的instance即为SingletonEnum类型的引用所以得到它就可以调用枚举中的方法了。
 借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
 */

public enum SingletonEnum {

    instance;

    private SingletonEnum() {
    }

    public void whateverMethod() {

    }

    // SingletonEnum.instance.method();

}

建造者模式

建造模式是对象的创建模式。建造模式可以将一个产品的内部表象(internal representation)与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

java 复制代码
public abstract class Builder {

    public abstract void setPart(String name, String type);

    public abstract Product getProduct();
}
java 复制代码
 public class ConcreteBuilder extends Builder {

     private Product product = new Product();
 
     @Override
     public void setPart(String name, String type) {
         product.setName(name);
         product.setType(type);
     }
 
     @Override
     public Product getProduct() {
         return product;
     }
 }
java 复制代码
 // 店长
 Director director = new Director();
 // 得到宝马汽车,内部实现提取宝马汽车的详情操作
 Product product = director.getBProduct();
 // 展示汽车信息
 product.showProduct();

工厂模式

简单列一下这个模式的家族:

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
java 复制代码
/**
 * Created by jingbin on 2016/10/23.
 * 简单工厂模式
 */

public class SimpleRoujiaMoFactory {

    public RoujiaMo creatRoujiaMo(String type) {
        RoujiaMo roujiaMo = null;
        switch (type) {
            case "Suan":
                roujiaMo = new ZSuanRoujiaMo();
                break;
            case "La":
                roujiaMo = new ZLaRoujiaMo();
                break;
            case "Tian":
                roujiaMo = new ZTianRoujiaMo();
                break;
            default:// 默认为酸肉夹馍
                roujiaMo = new ZSuanRoujiaMo();
                break;
        }
        return roujiaMo;
    }
}
java 复制代码
 public RoujiaMo creatRoujiaMo(String type) {
     RoujiaMo roujiaMo = null;
     switch (type) {
         case "Suan":
             roujiaMo = new ZSuanRoujiaMo();
             break;
         case "La":
             roujiaMo = new ZLaRoujiaMo();
             break;
         case "Tian":
             roujiaMo = new ZTianRoujiaMo();
             break;
         default:// 默认为酸肉夹馍
             roujiaMo = new ZSuanRoujiaMo();
             break;
     }
     return roujiaMo;
 }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

java 复制代码
/**
 * Created by jingbin on 2016/10/24.
 *
 * 在北京和西安 开分店:
 * 工厂方法模式:
 * 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。
 * 工厂方法模式把类实例化的过程推迟到子类。
 *
 * 对照定义:
 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
 */

public abstract class RoujiaMoStore {

    public abstract RoujiaMo sellRoujiaMo(String type);

//    public RoujiaMo sellRoujiaMo(String type) {
//
//        RoujiaMo roujiaMo = creatRoujiaMo(type);
//        roujiaMo.prepare();
//        roujiaMo.fire();
//        roujiaMo.pack();
//        return roujiaMo;
//
//    }

}
java 复制代码
public abstract RoujiaMo sellRoujiaMo(String type);
java 复制代码
/**
 * Created by jingbin on 2016/10/24.
 * 西安肉夹馍店   让分店自己去卖自己口味的肉夹馍
 */

public class XianRoujiaMoStore extends RoujiaMoStore {

    private XianSimpleRoujiaMoFactory factory;

    public XianRoujiaMoStore(XianSimpleRoujiaMoFactory factory) {
        this.factory = factory;
    }

    public RoujiaMo sellRoujiaMo(String type) {

        RoujiaMo roujiaMo = factory.creatRoujiaMo(type);
        roujiaMo.prepare();
        roujiaMo.fire();
        roujiaMo.pack();
        return roujiaMo;
    }

//    @Override
//    public RoujiaMo creatRoujiaMo(String type) {
//
//        RoujiaMo roujiaMo = null;
//        switch (type) {
//            case "suan":
//                roujiaMo = new XianSuanRoujiMo();
//                break;
//            case "tian":
//                roujiaMo = new XianKuRoujiMo();
//                break;
//            case "la":
//                roujiaMo = new XianlaRoujiMo();
//                break;
//            default:// 默认为 西安 酸肉夹馍
//                roujiaMo = new XianSuanRoujiMo();
//                break;
//        }
//        return roujiaMo;
//    }
}
java 复制代码
/**
 * Created by jingbin on 2016/10/23.
 * 西安 简单工厂模式:
 * 用来西安店生产自己店里的肉夹馍
 */

public class XianSimpleRoujiaMoFactory {

    public RoujiaMo creatRoujiaMo(String type) {
        RoujiaMo roujiaMo = null;
        switch (type) {
            case "Suan":
                roujiaMo = new XianSuanRoujiMo();
                break;
            case "La":
                roujiaMo = new XianKuRoujiMo();
                break;
            case "Tian":
                roujiaMo = new XianlaRoujiMo();
                break;
            default:// 默认为酸肉夹馍
                roujiaMo = new XianSuanRoujiMo();
                break;
        }
        return roujiaMo;
    }
}

抽象工厂模式

  • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
  • 对比定义:
    • 1、提供一个接口:public interface RouJiaMoYLFactroy
    • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
  • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
java 复制代码
/**
 * Created by jingbin on 2016/10/26.
 * 4、抽象工厂模式:
 * 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
 * 这定义有点绕口,算了,还是拿例子来说。
 * 继续卖肉夹馍,咱们生意这么好,难免有些分店开始动歪脑子,开始使用劣质肉等,砸我们的品牌。
 * 所以我们要拿钱在每个城市建立自己的原料场,保证高质量原料的供应。
 */

public interface RoujiaMoYLFactory {

    /**
     * 生产肉
     */
    public Meet creatMeet();

    /**
     * 生产一些原料
     */
    public YuanLiao creatYuanLiao();
}
java 复制代码
/**
 * Created by jingbin on 2016/10/26.
 * 西安的肉夹馍原料工厂,是西安的特色原料,还有其他分店的特色原料
 */

public class XianRoujiaMoYLFoctory implements RoujiaMoYLFactory {

    @Override
    public Meet creatMeet() {
        return new XianFreshMeet();
    }

    @Override
    public YuanLiao creatYuanLiao() {
        return new XianTeSeYuanLiao();
    }
}
java 复制代码
import android.util.Log;

/**
 * Created by jingbin on 2016/10/22.
 */

public abstract class RoujiaMo {

    protected String name;

    /**
     * 准备工作
     */
    public void prepare(RoujiaMoYLFactory roujiaMoYLFactory) {
        Meet meet = roujiaMoYLFactory.creatMeet();
        YuanLiao yuanLiao = roujiaMoYLFactory.creatYuanLiao();

        Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

    /**
     * 秘制设备--烘烤2分钟
     */
    public void fire() {
        Log.e("---RoujiaMo:", name + ": 肉夹馍-专用设备-烘烤");
    }

    /**
     * 使用你们的专用袋-包装
     */
    public void pack() {
        Log.e("---RoujiaMo:", name + ": 肉夹馍-专用袋-包装---end");
    }
}
java 复制代码
 /**
 * 准备工作
 */
public void prepare(RoujiaMoYLFactory roujiaMoYLFactory) {
    	Meet meet = roujiaMoYLFactory.creatMeet();
    	YuanLiao yuanLiao = roujiaMoYLFactory.creatYuanLiao();
    	Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
}

原型模式

原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

以获取多种形状为例,共分四步:

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)
java 复制代码
 public abstract class Shape implements Cloneable {
 
     private String id;
     protected String type;
 
     public abstract void draw();
 
     public String getId() {
         return id;
     }
 
     public void setId(String id) {
         this.id = id;
     }
 
     @Override
     public Object clone() {
         Object object = null;
         try {
             object = super.clone();
         } catch (CloneNotSupportedException e) {
             Log.e("--", e.getMessage());
         }
         return object;
     }
 }

2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

java 复制代码
 public class Circle extends Shape {
 
     public Circle() {
         type = "Circle";
     }
 
     @Override
     public void draw() {
         Log.e("---", "Inside Circle::draw() method.");
     }
     
 }
java 复制代码
/**
 * Created by jingbin on 2020-01-31.
 * 2. 创建扩展了上面抽象类的实体类。Rectangle 矩形
 */
public class Rectangle extends Shape {

    public Rectangle() {
        type = "Rectangle";
    }

    @Override
    public void draw() {
        Log.e("---", "Inside Rectangle::draw() method.");
    }


}
java 复制代码
/**
 * Created by jingbin on 2020-01-31.
 * 2. 创建扩展了上面抽象类的实体类。Square 正方形
 */
public class Square extends Shape {

    public Square() {
        type = "Square";
    }

    @Override
    public void draw() {
        Log.e("---", "Inside Square::draw() method.");
    }


}

3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

java 复制代码
 public class ShapeCache {
 
     private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();
 
     public static Shape getShape(String shapeId) {
         Shape shapeCache = shapeMap.get(shapeId);
         return (Shape) shapeCache.clone();
     }
 
     // 对每种形状都运行数据库查询,并创建该形状
     // shapeMap.put(shapeKey, shape);
     // 例如,我们要添加三种形状
     public static void loadCache() {
         Circle circle = new Circle();
         circle.setId("1");
         shapeMap.put(circle.getId(), circle);
 
         Rectangle rectangle = new Rectangle();
         rectangle.setId("2");
         shapeMap.put(rectangle.getId(), rectangle);
 
         Square square = new Square();
         square.setId("3");
         shapeMap.put(square.getId(), square);
     }
 }

4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

java 复制代码
 // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache.loadCache();
Shape shapeCache1 = ShapeCache.getShape("1");
Shape shapeCache2 = ShapeCache.getShape("2");
Shape shapeCache3 = ShapeCache.getShape("3");

参考材料

相关代码github地址:GitHub - youlookwhat/DesignPattern: 📚 Java 23种设计模式全归纳

相关文章:Java 23种设计模式全归纳 | 完结版-腾讯云开发者社区-腾讯云 (tencent.com)

相关推荐
捕鲸叉3 小时前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式
小小小妮子~4 小时前
框架专题:设计模式
设计模式·框架
先睡4 小时前
MySQL的架构设计和设计模式
数据库·mysql·设计模式
Damon_X12 小时前
桥接模式(Bridge Pattern)
设计模式·桥接模式
越甲八千16 小时前
重温设计模式--享元模式
设计模式·享元模式
码农爱java18 小时前
设计模式--抽象工厂模式【创建型模式】
java·设计模式·面试·抽象工厂模式·原理·23种设计模式·java 设计模式
越甲八千18 小时前
重温设计模式--中介者模式
windows·设计模式·中介者模式
犬余18 小时前
设计模式之桥接模式:抽象与实现之间的分离艺术
笔记·学习·设计模式·桥接模式
Theodore_102220 小时前
1 软件工程——概述
java·开发语言·算法·设计模式·java-ee·软件工程·个人开发
越甲八千21 小时前
重拾设计模式--组合模式
设计模式·组合模式