您的位置:首页 > 汽车 > 新车 > 软件工程——设计模式之创建型模式(单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。)

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

2024/7/3 22:22:56 来源:https://blog.csdn.net/batcat560/article/details/137522600  浏览:    关键词:软件工程——设计模式之创建型模式(单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。)

目录

设计模式的六大原则

单例模式

抽象工厂模式

建造者模式

工厂模式

原型模式

设计模式的六大原则

  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

/*** 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();}
  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.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;}
  • 内部类[推荐用]:SingletonIn.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;}
}
  • 枚举[推荐用]:SingletonEnum.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

public abstract class Builder {public abstract void setPart(String name, String type);public abstract Product getProduct();
}
  • 建造者对应实现类:ConcreteBuilder

  •  public class ConcreteBuilder extends Builder {private Product product = new Product();@Overridepublic void setPart(String name, String type) {product.setName(name);product.setType(type);}@Overridepublic Product getProduct() {return product;}}
  • 店长Director取汽车:

 // 店长Director director = new Director();// 得到宝马汽车,内部实现提取宝马汽车的详情操作Product product = director.getBProduct();// 展示汽车信息product.showProduct();

工厂模式

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

  • 1、静态工厂模式

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

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.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;}
}

 

 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

/*** 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;
//
//    }}
public abstract RoujiaMo sellRoujiaMo(String type);
  • 具体实现抽象方法:XianRoujiaMoStore.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;
//    }
}
  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.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
/*** Created by jingbin on 2016/10/26.* 4、抽象工厂模式:* 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。* 这定义有点绕口,算了,还是拿例子来说。* 继续卖肉夹馍,咱们生意这么好,难免有些分店开始动歪脑子,开始使用劣质肉等,砸我们的品牌。* 所以我们要拿钱在每个城市建立自己的原料场,保证高质量原料的供应。*/public interface RoujiaMoYLFactory {/*** 生产肉*/public Meet creatMeet();/*** 生产一些原料*/public YuanLiao creatYuanLiao();
}
  • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
/*** Created by jingbin on 2016/10/26.* 西安的肉夹馍原料工厂,是西安的特色原料,还有其他分店的特色原料*/public class XianRoujiaMoYLFoctory implements RoujiaMoYLFactory {@Overridepublic Meet creatMeet() {return new XianFreshMeet();}@Overridepublic YuanLiao creatYuanLiao() {return new XianTeSeYuanLiao();}
}
  • 准备时,使用官方的原料:RoujiaMo.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");}
}
 /*** 准备工作*/
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)

 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;}@Overridepublic Object clone() {Object object = null;try {object = super.clone();} catch (CloneNotSupportedException e) {Log.e("--", e.getMessage());}return object;}}

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

 public class Circle extends Shape {public Circle() {type = "Circle";}@Overridepublic void draw() {Log.e("---", "Inside Circle::draw() method.");}}

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

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

 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 中的形状的克隆。

 // 使用 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)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com