文章目录
- 面向对象设计的基本原则:
- 单例模式 (常用)
- 常见应用场景:
- 常见的五种单例模式实现方式:
- 五种单例模式的代码实现:
- 工厂模式 (常用)
- 工厂模式的分类:
- 应用场景
- 三种模式下的代码实现和UML图:
- 建造者模式 (常用)
- 代码实现和UML图
- 原型模式
- 创建型模式总结
面向对象设计的基本原则:
- OCP (开闭原则, Open-Closed Principle) : 一个软件的实体应当对扩展开放,对修改关闭。即当要添加一个新功能时,不要修改已有的类,而是重新写一个类实现这个功能。
- DIP (依赖倒转原则, Dependence Inversion Principle ) : 要针对接口编程,不要针对实现编程。
- LoD (迪米特法则, Law of Demeter) : 只与你直接的朋友通信,而避免和陌生人通信。
单例模式 (常用)
作用:
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
常见应用场景:
- Windows的Task Manager (任务管理器)就是很典型的单例模式
- windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站-直维护着仅有的一个实例。
- 项目中,读取配置文件的类, 一般也只有一个对象。 没有必要每次使用配置文件数据,每次new-个对象去读取。
- 网站的计数器, 一般也是采用单例模式实现,否则难以同步。
- 应用程序的日志应用, 一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态 ,因为只能有一个实例去操作,否则内容不好追加。
- 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
- 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
- Application也是单例的典型应用( Servlet编程中会涉及到)
- 在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理
在servlet编程中,每个Servlet也是单例 - 在spring MVC框架/struts1框架中,控制器对象也是单例
单例模式的优点:
- 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
- 单例模式可以在系统设置全局的访问点 ,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理
常见的五种单例模式实现方式:
- 主要:
- 饿汉式(线程安全,调用效率高。但是,不能延时加载。)
- 懒汉式(线程安全,调用效率不高。 但是,可以延时加载。);在用的使用才加载。并发效率资源第。
- 其他:
- 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用);这个模式将同步内容下方到if内部,提高了执行的效率不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了。
- 静态内部类式(线程安全,调用效率高。但是,可以延时加载);也是一种懒加载的方式。兼备了并发高效调用和延迟加载的优势!
- 枚举单例(线程安全,调用效率高,不能延时加载);实现简单,枚举本身就是单例模式。由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!
如何选用
单例对象占用资源少,不需要延时加载:
- 枚举式好于饿汉式
单例对象占用资源大,需要延时加载:
- 静态内部类式好于懒汉式
五种单例模式的代码实现:
饿汉模式:
/*
* 饿汉式单例模式
*/
public class SingletonDemo1 {
//初始化类时,立即加载这个对象(没有延时加载的优势,因为不一定要使用,立即加载可能会浪费资源)
//加载类时,因为创建对象是线程安全的,不需要添加关键字synchronized(加锁),所以饿汉式是天然线程安全的
private static SingletonDemo1 instance = new SingletonDemo1();
//将构造方法私有化
private SingletonDemo1(){
}
//提供一个获得对象的方法,方法没有同步,调用效率高
public static SingletonDemo1 getInstance(){
return instance;
}
}
懒汉式:
/*
* 懒汉式单例模式
*/
public class SingletonDemo2 {
//类初始化时,不立即初始化对象(延时加载,在要使用的时候才进行加载)
private static SingletonDemo2 instance;
//将构造方法私有化
private SingletonDemo2(){
}
//方法同步,调用效率高
public static synchronized SingletonDemo2 getInstance(){
if(instance==null){
instance = new SingletonDemo2();
}
return instance;
}
}
双重检测锁式:
/*
* 双重检测锁式单例模式
*/
public class SingletonDemo3 {
private static SingletonDemo3 instance = null;
//将构造方法私有化
private SingletonDemo3(){
}
//这个模式将同步内容下方到if内部,提高了执行的效率不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了。
public static SingletonDemo3 getInstance(){
if(instance==null){
SingletonDemo3 sc;
synchronized(SingletonDemo3.class){
sc = instance;
if(sc==null){
synchronized(SingletonDemo3.class){
if(sc==null){
sc = new SingletonDemo3();
}
}
instance = sc;
}
}
}
return instance;
}
}
静态内部类式:
/*
* 静态内部类式单例模式
*/
public class SingletonDemo4 {
/*
* 要点:
-外部类没有static属性,则不会像饿汉式那样立即加载对象。
-只有真正调用getInstance0,才会加载静态内部类。加载类时是线程安全的。 instance是static final
类型,保证了内存中只有这样一个实例存在 ,而且只能被赋值一次,从而保证了线程安全性.
-兼备了并发高效调用和延迟加载的优势!
*/
private static class SingletonClassInstance{
private static final SingletonDemo4 instance = new SingletonDemo4();
}
public static SingletonDemo4 getinstance(){
return SingletonClassInstance.instance;
}
//将构造方法私有化
private SingletonDemo4(){
}
}
枚举式:
/*
* 枚举式单例模式
*/
public enum SingletonDemo5 {
//这个枚举元素,本事就是单例; 缺点是不能延时加载
INSTANCE;
//添加自己需要的操作
public void singletonOperarion(){
}
}
以上五种单例模式除了枚举式,其他的都有可能会被反射和反序列化破解;下面方式可以防止这种情况的发生。
import java.io.ObjectStreamException;
/*
* 懒汉式单例模式(防止通过反射和反序列化进行破解)
*/
public class SingletonDemo6 {
//类初始化时,不立即初始化对象(延时加载,在要使用的时候才进行加载)
private static SingletonDemo6 instance;
//将构造方法私有化
private SingletonDemo6(){
//防止通过反射使用私有的构造器
if(instance!=null){
throw new RuntimeException();
}
}
//方法同步,调用效率高
public static synchronized SingletonDemo6 getInstance(){
if(instance==null){
instance = new SingletonDemo6();
}
return instance;
}
//防止通过反序列化破坏单例模式,如果定义了readResolve()则直接返回此方法指定的对象。不需要单独再创建新对象
private Object readResolve() throws ObjectStreamException{
return instance;
}
}
五种单例模式在多线程下的效率情况:
注:数据在不同的环境下可能会有点偏差。
工厂模式 (常用)
作用:
实现了创建者和调用者的分离。
核心本质:
- 实例化对象,用工厂方法代替new操作。
- 将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
工厂模式的分类:
- 简单工厂模式:
- 用来生产同一等级结构中的任意产品。 (对于增加新的产品,需要修改已有代码)
- 虽然某种程度不符合设计原则,但实际使用最多。
- 方法模式:
- 用来生产同一等级结构中的固定产品。( 支持增加任意产品);缺点:需要的类可能太多了。
- 不修改已有类的前提下,通过增加新的工厂类实现扩展。
- 抽象工厂模式:
- 用来生产不同产品族的全部产品。( 对于增加新的产品,无能为力;支持增加产品族)
- 不可以增加产品,可以增加产品族
应用场景
- JDK中Calendar的getInstance方法
- JDBC中Connection对象的获取
- Hibernate中SessionFactory创建Session
- spring中IOC容器创建管理bean对象
- XML解析时的DocumentBuilderFactory创建解析器对象
- 反射中Class对象的newInstance()
三种模式下的代码实现和UML图:
用于测试的类:
public interface Car {
void run();
}
public class Audi implements Car{
@Override
public void run() {
System.out.println("奥迪在跑");
}
}
public class Byd implements Car{
@Override
public void run() {
System.out.println("比亚迪在跑");
}
}
简单工厂实现:
/*
* 简单工厂类
*/
public class CarFactory1 {
public static Car createAudi(){
return new Audi();
}
public static Car createByd(){
return new Byd();
}
}
测试类:
/*
* 简单工厂情况下
*/
public class Client02 {
public static void main(String[] args) {
Car c1 = CarFactory1.createAudi();
Car c2 = CarFactory1.createByd();
c1.run();
c2.run();
}
}
简单工厂下的UML图:
方法模式工厂:
工厂方法模式要点:
- 为了避免简单工厂模式的缺点,不完全满足OCP。
- 工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。
- 每一种产品都有一个工厂类对应,当需要添加产品时,只需要添加新的类即可,不需要修改原来的代码。
代码实现:
接口:
public interface CarFactory {
Car createCar();
}
奥迪工厂:
public class AudiFactory implements CarFactory{
@Override
public Car createCar() {
return new Audi();
}
}
比亚迪工厂:
public class BydFactory implements CarFactory{
@Override
public Car createCar() {
return new Byd();
}
}
测试类:
/*
* 使用方法工厂模式
*/
public class Client03 {
public static void main(String[] args) {
Car c1 = new AudiFactory().createCar();
Car c2 = new BydFactory().createCar();
c1.run();
c2.run();
}
}
方法工厂的UML图:
抽象工厂模式:
作用:
- 用来生产不同产品族的全部产品。( 对于增加新的产品,无能为力;支持增加产品族)
- 抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
代码实现:
引擎产品:
package abstractFactory;
/*
*引擎接口
*/
public interface Engine {
void run();
void start();
}
//高端引擎
class LuxuryEngine implements Engine{
@Override
public void run() {
System.out.println("转的快!");
}
@Override
public void start() {
System.out.println("启动快!可以自动暂停");
}
}
//低端引擎
class LowEngine implements Engine{
@Override
public void run() {
System.out.println("转的慢!");
}
@Override
public void start() {
System.out.println("启动慢!");
}
}
座椅产品:
package abstractFactory;
/*
* 座椅
*/
public interface Seat {
void massage();
}
//高端座椅
class LuxurySeat implements Seat{
@Override
public void massage() {
System.out.println("可以自动按摩");
}
}
//低端座椅
class LowSeat implements Seat{
@Override
public void massage() {
System.out.println("不能自动按摩");
}
}
轮胎产品:
package abstractFactory;
//轮胎接口
public interface Tyre {
void revolve();
}
//高端轮胎
class LuxuryTyre implements Tyre{
@Override
public void revolve() {
System.out.println("旋转不磨损");
}
}
//低端轮胎
class LowTyre implements Tyre{
@Override
public void revolve() {
System.out.println("旋转磨损");
}
}
工厂接口:
package abstractFactory;
public interface CarFactory {
Engine CreateEngine();
Seat CreateSeat();
Tyre CreateTre();
}
高端产品族工厂:
package abstractFactory;
/*
* 高端产品族工厂
*/
public class LuxuryCarFactory implements CarFactory{
@Override
public Engine CreateEngine() {
return new LuxuryEngine();
}
@Override
public Seat CreateSeat() {
return new LuxurySeat();
}
@Override
public Tyre CreateTre() {
return new LuxuryTyre();
}
}
低端产品族工厂:
package abstractFactory;
/*
* 低端产品族工厂
*/
public class LowCarFactory implements CarFactory{
@Override
public Engine CreateEngine() {
return new LowEngine();
}
@Override
public Seat CreateSeat() {
return new LowSeat();
}
@Override
public Tyre CreateTre() {
return new LowTyre();
}
}
测试类:
package abstractFactory;
public class Client {
public static void main(String[] args) {
CarFactory factory = new LuxuryCarFactory();
Engine e = factory.CreateEngine();
e.run();
e.start();
}
}
建造者模式 (常用)
应用场景:
- 我们要建造一个复杂的产品。比如:神州飞船,Iphone。这个复杂的产品的创建。有这样个问题需要处理:装配这些子组件是不是有个步骤问题?
- 实际开发中,我们所需要的对象构建时,也非常复杂,有很多步骤需要处理时。
建造模式的本质:
- 分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)。从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况下使用。
- 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
开发中应用场景:
- StringBuilder类的append方法
- SQL中的PreparedStatement
- JDOM中, DomBuilder、SAXBuilder
代码实现和UML图
飞船和零件类:
package 建造者模式;
/*
* 宇宙飞船
*/
public class AirShip {
private OrbitalModule orbitalModule; //轨道舱
private Engine engine; //发动机
private EscapeTower escapeTower; //逃逸塔
public void launch(){
System.out.println("发射!");
}
public OrbitalModule getOrbitalModule() {
return orbitalModule;
}
public void setOrbitalModule(OrbitalModule orbitalModule) {
this.orbitalModule = orbitalModule;
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
public EscapeTower getEscapeTower() {
return escapeTower;
}
public void setEscapeTower(EscapeTower escapeTower) {
this.escapeTower = escapeTower;
}
}
class OrbitalModule {
private String name;
public OrbitalModule(String name) {
super();
this.name = name;
}
}
class Engine {
private String name;
public Engine(String naem) {
super();
this.name= naem;
}
public String getName() {
return name;
}
}
class EscapeTower {
private String name;
public EscapeTower(String name) {
super();
this.name = name;
}
}
建造者接口:
/*
* 建造者接口
*/
public interface AirShipBuilder {
Engine builderEngine();
OrbitalModule builderOrbitaModule();
EscapeTower builderEscapeTower();
}
组装者接口:
public interface AirShipDirector {
//组装飞船对象
AirShip directAirShip();
}
构建者类:
package 建造者模式;
/*
* 构建者类
*/
public class SxtAirShipBuilder implements AirShipBuilder{
@Override
public Engine builderEngine() {
System.out.println("构建发动机");
return new Engine("发动机");
}
@Override
public OrbitalModule builderOrbitaModule() {
System.out.println("构建逃逸塔");
return new OrbitalModule("逃逸塔");
}
@Override
public EscapeTower builderEscapeTower() {
System.out.println("构建轨道舱");
return new EscapeTower("轨道舱");
}
}
组装者类:
package 建造者模式;
/*
* 组装者类,用于将零件组装成对象
*/
public class SxtAirshipDirector implements AirShipDirector{
private AirShipBuilder builder;
public SxtAirshipDirector(AirShipBuilder builder){
this.builder = builder;
}
@Override //将组件组装成飞船
public AirShip directAirShip() {
Engine e = builder.builderEngine();
OrbitalModule o = builder.builderOrbitaModule();
EscapeTower et = builder.builderEscapeTower();
//装配成飞船对象
AirShip ship = new AirShip();
ship.setEngine(e);
ship.setEscapeTower(et);
ship.setOrbitalModule(o);
return ship;
}
}
测试类:
public class Client {
public static void main(String[] args) {
AirShipDirector director = new SxtAirshipDirector(new SxtAirShipBuilder());
AirShip ship = director.directAirShip();
System.out.println(ship.getEngine().getName());
ship.launch();
}
}
UML图:
原型模式
原型模式介绍:
- 通过new产生一 个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点
- 优势有:效率高(直接克隆,避免了重新执行构造过程步骤)。
- 克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出的对象的属性值完全和原型对象相同。并且克隆出的新对象改变不会影响原型对象。然后,再修改克隆对象的值。
原型模式实现:
- Cloneable接口和clone方法
- Prototype(原型)模式中实现起来最困难的地方就是内存复制操作 ,所幸在Java中提供了clone()方法替我们做了绝大部分事情。
开发中的应用场景
- 原型模式很少单独出现,-般是和工厂方法模式一起出现,通过clone的方法创建一个对象 ,然后由工厂方法提供给调用者。
- spring中bean的创建实际就是两种:单例模式和原型模式。( 当然,原型模式需要和工厂模式搭配起来)
代码实现:
package 原型模式;
import java.sql.Date;
public class Sheep implements Cloneable{
private String sname;
private Date birthday;
//重写克隆方法
protected Object clone() throws CloneNotSupportedException{
Object obj = super.clone(); //直接调用Object对象的clone()方法
//添加如下代码实现深克隆(deep Clone);如果没有进行深坑,克隆出来的属性会指向同一个对象
Sheep s = (Sheep) obj;
s.birthday = (Date) this.birthday.clone(); //把属性也进行克隆
return obj;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Sheep() {
}
public Sheep(String sname, Date birthday) {
super();
this.sname = sname;
this.birthday = birthday;
}
}
测试类:
package 原型模式;
import java.sql.Date;
/**
*
* 测试原型模式(深克隆)
*
*/
public class Client {
public static void main(String[] args) throws Exception {
Date d = new Date(123456567L);
Sheep s1 = new Sheep("shao利", d);
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());
Sheep s2 = (Sheep)s1.clone();
d.setTime(666666666666L);
s2.setSname("多利");
System.out.println(s2);
System.out.println(s2.getSname());
System.out.println(s2.getBirthday());
}
}
创建型模式总结
创建型模式:都是用来帮助我们创建对象的!
单例模式:
- 保证一个类只有一个实例,并且提供一 个访问该实例的全局访问点。
工厂模式:
- 简单工厂模式:
用来生产同一等级结构中的任意产品。( 对于增加新的产品,需要修改已有代码) - 工厂方法模式:
用来生产同一等级结构中的固定产品。( 支持增加任意产品) - 抽象工厂模式:
一用来生产不同产品族的全部产品。( 对于增加新的产品,无能为力;支持增加产品族)
建造者模式:
- 分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)。从而可以构造出复杂的对象。
- 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
原型模式:
- 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
更多推荐
创建型模式大全(Java讲解)
发布评论