初识Java设计模式学习

Title:Java设计模式学习
Author:ychhh_

设计模式概述

设计模式目的

  • 编写过程中,程序员面临着耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性等多方面的挑战,设计模式是为了让程序具有更好:

    • 代码重用性
    • 可读性
    • 可靠性
    • 是程序具有低耦合性,高内聚性
  • 设计模式七大原则:

    • 单一职责原则
    • 接口隔离原则
    • 依赖倒转原则(面向接口编程)
    • 里氏替换原则
    • 开闭原则
    • 迪米特法则
    • 合成复用原则

七大原则

单一职责原则
  • 基本介绍:对类来说,一个单一类只负责一个职责。若一个类负责多个值则,如:类A拥有这则1和值则2,当值则1发生改变而影响类A,则可能导致值则2的错误,所以需要将类A颗粒化为类A1和类A2
  • 单一职责注意事项:
    • 降低类的复杂度,一个类只负责一个职责
    • 提高类的可读性,可维护性
    • 降低变更引起的风险
    • 通常情况下需要遵守单一职责的原则,但在类的方法特别少的情况下可以不遵守单一职责
  • Attention:
    • 对于if…else语句需要谨慎使用,if…else使得代码的耦合程度太高,在必须使用if…else…时考虑使用构造方法或构造类的形式来代替if…else
接口隔离原则
  • 基本介绍:

    • 客户端不应该依赖不需要的接口,即一个类对另一个类的依赖需要建立在最小耦合的接口之上
  • 解决方法:若发生了接口的冗余,则通过接口的分解方式,将一个接口分解为多个子接口

依赖倒转原则(面向接口编程)
  • 基本介绍:
    • 高层模块不应该依赖于低层模块,二者都应该依赖于其抽象
    • 抽象不应该依赖细节,细节应该依赖于抽象
    • 依赖倒转即面向接口编程
  • 注意事项:
    • 底层模块尽量有抽象类或接口或两者都有,这样使得程序的稳定性更好
    • 变量的声明类型尽量是抽象类或接口,这样使得变量引用和实际对象间有一层缓冲层,有利于程序的扩展和优化
    • 继承时遵循里氏替换原则
里氏替换原则
  • 基本介绍:

    如果对每个类型为T1的对象o1,有每个类型为T2的对象o2,若将程序所有为o1的地方改为o2,则程序不发生改动,则T2时T1的子类。即引用基类的地方都能透明的使用子类

    • 在使用继承时子类尽量不要重写父类方法
    • 继承使两个类的耦合程度增强了,在适当的情况下可以通过聚合,组合,依赖来解决
  • 对于继承的解耦合:

    • 将原来的继承关系进行接触
    • 创建一个公共的Base类,最抽象的类,使原先具有继承关系的两个类都来继承这个类
    • 在其中一个类里(一般为当初的子类),创建(当初父类)变量
    • 使用该对象的方法
开闭原则
  • 基本介绍:

    • 对扩展(提供者)开放,对修改(使用者)封闭。用抽象扩展框架,用实现修改细节
    • 当软件的需求发生变化时尽量通过软件的实体行为来发生变化,而不是通过修改已有的代码来实现
    • 编程中遵循的其他原则,以及设计模式的目的就是遵循开闭原则
  • 解决方法:

    • 通过实现接口和抽象类来将实体进行抽离
    • 在实现的接口的子类或实现抽象类的子类中进行细节化,从而降低了耦合性
迪米特法则
  • 基本介绍:

    • 一个类应对其他类保持最小的了解

    • 类与类之间的关系越密切,其耦合度越大

    • 迪米特法则:

      即最少知到原则,一个类对自己依赖的类知到越少越好。也就是说,不管被依赖的类有多复杂,都尽量封装自己类内部,对外只提供public方法接口

      • 直接朋友:在类 的内部直接调用、声明、使用的类
      • 简介朋友:在方法的内部声明的局部变量(此时违反了迪米特法则)
  • 个人理解:

    • 即设计需要按照一定的拓扑关系,不能越级调用,需要按照流程来执行想要的功能
  • 注意事项:

    • 迪米特法则只要求降低耦合而不是完全没有耦合
合成复用原则
  • 基本介绍:能够使用合成/聚合的方式就不要使用继承
  • 注意事项:
    • 找出可能变化之处,并将其独立出来
    • 针对接口编程,而不是针对实现编程
    • 为了交互对象而实现松耦合

UML类图

  • 类和类之间的关系:依赖,泛化,实现,关联,聚合,组合

    • 依赖:

      只要是在类中用到了对方就存在依赖关系(最基本的类之间的关系,如果没有这个类,连编译都通过不了)

    • 泛化(继承):

      依赖关系的特例

    • 实现:

      实现接口,实现关系也为依赖关系

    • 关联:

      1. 表示类与类之间的特例也为依赖关系
      2. 关联具有导航性,即一对一或是一对多

      一对一:

      
      classDiagram
      	class Person{
      		IDCard card;
      	}
      

      双向一对一:

      Person
      IDCard card;
      IDCard
      Person person;
    • 聚合:

      ​ 各部分成员之间可以分离,既可以独立存在

      Computer
      Mouse mouse;
      Keyboard board;
      Keyboard
      Mouse
    • 组合:

      ​ 各部分成员之间不可以分离,即不可以独立存在,必须共生共灭

      People
      Head head = new Head()
      Nose nose = new Nose()

设计模式

基本概念
  • 设计模式分为三类,共23种:
    1. 创建型模式
      • 单例模式
      • 抽象工厂模式
      • 原型模式
      • 建造者模式
      • 工厂模式
    2. 结构型模式
      • 适配器模式
      • 桥接模式
      • 装饰模式
      • 组合模式
      • 外观模式
      • 享元模式
      • 代理模式
    3. 行为型模式
      • 模板方法模式
      • 命令模式
      • 访问者模式
      • 迭代器模式
      • 观察者模式
      • 中介者模式
      • 备忘录模式
      • 解释器模式
      • 状态模式
      • 策略模式
      • 职责链模式
单例模式
  • 概念:单例模式即在软件系统中,对某个类只能存在一个对象,并且该类只提供一个取个该实例的方法(静态方法)
饿汉式
  1. 静态常量写法

    class Hungry1{
         
        // 隐藏构造器,使得类外无法创建对象	
        private Hungry1() {
         
    
        }
        // 创建静态对象
        static final  private Hungry1 h1 = new Hungry1();
    
        // 提供静态对象接口
        static Hungry1 getHungrt() {
         
            return h1;
        }
    }
    
    • 优点:在类装载的时候就完成了实例化,避免了线程同步问题
    • 缺点:在类装载的过程中就完成了实例化,没有达到lazyloading的效果。如果从未使用过该实例,则会造成内存的浪费。这种基于ClassLoader的机制避免了多线程问题,但导致类加载的方式有很多,,因此不能确定其他方式不会造成类的加载,从而无法达到lazyloading
  2. 静态代码块写法

    class Hungry1{
         
    	private Hungry1() {
         
    		
    	}
    	
    	static final  private Hungry1 h1;
    	
    	static {
         
    		h1 = new Hungry1();
    	}
    	
    	
    	static Hungry1 getHungrt() {
         
    		return h1;
    	}
    }
    
    
    • 优缺点同上
懒汉式
  1. 线程不安全方式

    class Hungry2{
         
        private Hungry2() {
         
    
        }
    
        static private  Hungry2 h2;
    
        static Hungry2 getHungry() {
         
            if(h2 == null) {
         
                h2 = new Hungry2();
                return h2;
            }
            else return h2;
        }
    }
    
    
    • 优点:起到了lazyloading的效果

    • 缺点:只能在单线程下使用,但是由于存在

      if(h2 == null) {
             
                h2 = new Hungry2();
                return h2;
            }
      

      语句,所以存在线程安全问题,不可以在多线程并发的执行(除非专门控制并发)

    • 注意事项:在开发过程中尽量不要使用该方式实现单例模式


2. 线程安全式(同步方法方式)

class Hungry2{
   
	private Hungry2() {
   
		
	}
	
	static private  Hungry2 h2;
	
	public static synchronized Hungry2 getHungry() {
   
		if(h2 == null) {
   
			h2 = new Hungry2();
			return h2;
		}
		else return h2;
	}
}
// 添加syn关键字,保证线程安全
  • 优点:保证了线程的同步,解决了线程不安全的问题
  • 缺点:使程序的效率变低,需要互斥的执行该函数
  1. 线程安全式(同步代码块形式)

    错误方式,不存在!!!!

双重检查
class Hungry3{
   
	
	private Hungry3() {
   
		
	}
	
	static private volatile Hungry3 h3;
	
	public static Hungry3 getInstance() {
   
		if(h3 == null) {
   
			synchronized (Hungry3.class) {
   
				if(h3 == null)h3 = new Hungry3();
				
			}
		}
		return h3;
	}
}

  • 优点:Double-Check概念是多线程经常用到的单例方法,进行了两次的null值判断且使用了syn关键词进行同步,既保证了线程安全又保证了高效的处理和懒加载
静态内部类
public class StaticInnerClass {
   
	
	@Test
	public void test() {
   
		
	}

}
class Static{
   
	private Static() {
   
		
	}
	
	
	private static class StaticInner{
   
		private static Static instance = new Static();
	}
	
	public static Static getInstance() {
   
		return StaticInner.instance;
	}
}

  • 由于静态内部类的特殊性,在外部类装载的时候内部类不会进行装载,因此保证了懒加载,又因为内部类只会装载一次,因此保证了线程的安全
枚举类
package SingleInstance;

import org.junit.jupiter.api.Test;

public class EnumClass {
   
	@Test
	public void test() {
   
		Enum e1 = Enum.Instance;
		Enum e2 = Enum.Instance;
		System.out.println(e1 == e2);
	}

}
enum Enum{
   
	Instance();
	
	private Enum() {
   
		
	}
	
	
}
  • 枚举类的机制保证了线程的安全
单例模式注意
  • 单例模式保证了系统内存内只有一个对象,对于需要频繁创建和销毁的对象,使用单例模式可以提高系统的效率

  • 想要实例化一个单例时,使用的是相应的获取方法而不是使用new

  • 单例模式使用的场景:

    • 需要频繁创建和销毁对象的场景

    • 创建对象耗时或耗费资源过多但又经常用到的对象

      若能确保单线程的情况下:饿汉式(静态常量、静态代码块)

      多线程情况下:双重检查,枚举类,静态内部类

工厂模式
简单工厂模式
Pizza
Attributes
OrderPizza
Factory factory;
Factory
Pizza getPizza()
BJPizza
TJPizza
package Factory.SimpleFactory;

public class Factory {
   
	
	public Pizza getPizza(String name) {
   
		Pizza pizza = null;
		 if(name.equals("BJ") || name.equals("TJ"))
			 pizza = new Pizza(name);
		 
		 return pizza;
		
	}

}

package Factory.SimpleFactory;

import org.junit.jupiter.api.Test;

public class OrderPizza {
   
	
	private Factory factory = new Factory();
	private Pizza pizza = null;
	
	
	@Test
	public void getPizza() {
   
		String name = "BJ";
		
		pizza = factory.getPizza(name);
		
		if(pizza == null)
			System.out.println("no");
		else
			System.out.println("yes");
		
	}
	
	

}

package Factory.SimpleFactory;

public class Pizza {
   
	public Pizza(String name) {
   
		this.name = name;
	}
	
	String name;
	
}

  • 个人理解:
    • 简单工厂模式为对于种类较少的多个同种基类的创建,使用一个类进行菜单的作用,利用菜单进行分发,使用工厂类进行创建
工厂方法模式
Pizza
BJPepperPizza
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值