java的设计模式

设计模式---固定的模式    每种模式是用来解决某一类问题

1.设计模式   

        学习好的设计经验,可以:

                提高我们的编程思维能力,是的设计更加标准化,

                提高程序代码的复用性,可扩展性,灵活性....

                提高阅读源码的能力

                在大型项目中,在新添加功能的时候,最好不要影响之前的代码.

2.UML建模语言

2.1类与接口

        统一建模语言(Unified Modeling Language,UML) 在软件设计之初,需要通过uml建模语言来分析和设计软件中需要的类与类(接口)之间关系, 以静态图形的方式进行表达, 这个图形成为类图(uml类图).

        一般情况下都是架构级别的开发人员才会使用.

类图中要素:

类:

接口:

简单的类图:

2.2类之间的关系

1.继承关系

        类继承类

        接口继承接口

        is-a关系  xx是xx

2.实现关系

        类实现接口

3.依赖关系

        use-a关系  在xx中用到xx

        在一个类中的方法里面,使用到了另一个类,  关系弱,具有临时性(方法运行结束,关系就结束了)

4.关联关系

        把B类作为A的成员变量

        has-a   xx有xx

        人关联手机

        单向关联

        双向关联

        自关联

关联关系根据关系的强弱又分为:

1.聚合关系

        也是关联的一种,  是整体和部分的关系,列如学校和老师支之间的关系,学校如果不存在了,

老师可以独立的存在

2.组合关系

是一种更强烈的关联关系, 例如头和嘴的关系,  头不存在了,嘴也就不存在了.

3.面向对象设计原则

3.1面向对象:

        面向对象是一种编程思想,  面向过程是关注实现的步骤,每个步骤定义一个函数,调用函数执行即可.

        面向对象关注的是谁(对象)来执行,把具有相同属性和行为的一类事物(对象)进行抽象成类,

        然后再通过类实例化出一个个具体的对象,使用的具体的对象.

类包含:

        成员变量(属性) 名词

        成员方法(行为) 动词

        构造方法(用来为刚创建的对象的成员进行初始化赋值)

3.2面向对象特征

封装:

        误区:把封装理解为包装了

        使用访问权限修饰符把类中某些成员隐藏起来,不让直接访问,为私有成员提供特定的公共方法进行访问

        private  String name;

继承:

        子继承父

        可以继承父类中成员(功能),提高代码代码的复用性

        子类可以对父类方法进行重写

多态:

        同一个事物,在不同时刻表现不同的状态

        父类的引用指向子类对象

public void feedAnimal(Animal animal){
            animal.eat();
  }

        多态提高程序设计的扩展性(在新增功能时候,只添加新类,尽可能少的修改原来的代码),  满足开闭原则,对修改关闭

抽象类:被abstract修饰的类

        一个不完整的类(里面包含抽象方法)就可以定义抽象类,一般在类体系结构的顶层类,大多都是抽象类.

抽象类特点:

        不能实例化对象.

        其他功能和正常类一样

接口:

        接口可以理解为是一种特殊的抽象

        接口重点在于定义功能(抽象方法), 不能定义成员变量,  即使定义也只能定义静态常量

        接口同样不能被实例化对象, 由子类实现,重写其中的抽象方法.

什么时候用抽象类,什么是用接口?

当还需要定义成员变量,构造方法,具体方法时,应该使用抽象类

当只定义功能时,使用接口.

4.面向对象设计原则

        在复杂的程序设计时,如果没有好的设计,在后期扩展功能时就很麻烦.

        所以好的设计原则,可以提升程序设计的水平(可复用性,可维护性/可扩展性

4.1单一职责

​    一个类只负责一件事情.

4.2开闭原则

​     开闭原则 即  对修改关闭,对扩展开放  在增加新功能时,通过扩展一个新类来实现功能,尽量少的修改之前的代码

4.3接口隔离

把接口粒度更小,把同一类 的功能定义在一个接口中, 不要把所有的功能定义在一个接口中,这样实现类会继承过来一些不需要的功能过来

4.4依赖倒置原则

   编程实现不应该依赖于底层实现(实现类),而是应该依赖于上层的抽象,

   先根据实际情况,进行分析,设计出接口/抽象类,在抽象层中定义好功能,  底层实现根据上层的定义来具体实现即可.

4.5组合聚合复用原则

   如果在B类中需要复用A类中的某些方法, 除了让B类继承A类之外, 还可以在B类中关联A类, 在B类中依赖A类.

​    只是为了复用某几个方法,使用继承的代价要高一些,因为B类会把A类中所有的功能继承过来,以及A类的父类

4.6里氏替换原则

   在使用继承时,  在使用父类时,如果将其换成子类,也要保证功能不会受影响.

   当子类继承父类后,重写了父类中的方法, 这时如果把父类替换成子类,那么会影响父类原来的功能.

   如何避免:  如果子类需要重写父类中的方法,那么将父类定义为抽象类

4.7迪米特原则

​    只跟朋友联系,不和陌生人说话

​    举例:  明星  不直接与  粉丝,公司进行接触,   让明星,粉丝,公司通过经济人产生联系

5.单例模式

单例模式解决一个类在一个项目中只能创建一个对象.

1. 单例对象只能由单例类自己创建

2. 对外提供一个可获得单例对象的方法

单例模式分为:

        饿汉式单例:

                好处: 不存在线程安全问题 

                不足: 启动时创建对象,启动时间会变长.        

/*
   饿汉式单例:启动时创建对象,启动时间会变长.
 */
public class WIndow {

     private static WIndow window = new WIndow();

     private WIndow(){

     }


    public  static WIndow getWindow(){
        return  window;
    }

 
}

         

        懒汉式单例:

                在第一次获取单例对象时才创建       

                不足: 会存在线程安全问题

/*
   懒汉式单例: 在第一次获取单例对象时才创建
           不足: 会存在线程安全问题
 */
public class WIndow {

    /*
         加volatile主要解决的是禁止指令重排性
     */
     private volatile  static WIndow window = null;

     private WIndow(){

     }

     /*
        双重检索+volatile 的懒汉式单例
      */
    public  static WIndow getWindow(){
        if(window==null){
           synchronized (WIndow.class){
              if(window==null){
                  window = new WIndow();
              }
           }
        }
        return  window;
    }

  /*
       虽然解决了线程安全问题,但是效率低
     public synchronized static WIndow getWindow(){
        if(window==null){
            window = new WIndow();
        }
        return  window;
    }*/

  /*
  会存在线程安全问题
  public  static WIndow getWindow(){

         if(window==null){

             window = new WIndow();
         }
         return  window;
     }*/


}

系统中的Runtime类 就是一个饿汉式单例类

6.工厂模式

工程模式解决如何大量的创建对象

工厂模式分为工厂方法模式和抽象工厂模式

6.1简单工厂引入

        简单工厂一个工厂创建一类对象,需要根据传入的参数判断创建那个具体类的对象,

        不满足开闭原则, 添加新类型时,需要修改工厂代码

6.2工厂方法

为每一个具体的产品提供一个专门的工厂,专门负责生产这一具体产品,

满足了开闭原则,增加一个产品,就增加一个具体产品对应的工厂.

6.3抽象工厂

抽象工厂模式,解决了一个具体工厂只能造一个具体产品缺陷,

抽象工厂中,一个工厂可以创造同一个公司下多个不同类型的产品

7.模版方法模式

        定义一个模版类,在模版类中可以定义多个模版方法, 在模版方法中,把几个固定流程方法进行

调用,

        在这些方法中,有的实现都一样,在模版类中直接实现,有的方法实现有不同,把这些方法定义抽

象的,在子类中去实现,

        最终不同的功能使用不同的子类对象来调用模版方法,完成一个功能.

优点: 提高代码的复用性,把相同的功能在模版类中实现,不同的功能放在子类中实现.

在父类中的模版方法中,调用不同子类中的方法,实现反向控制, 增加新功能,扩展不同的子类即可,满

足了开闭原则

不足: 扩展功能需要添加子类,功能多了子类也就多了, 

​           在父类中反向调用子类中方法,增加了代码的阅读难度.

8.策略模式

解决了在不同内容之间选择的问题

先抽象,把要做的这件事情进行抽象,

不同做法,使用不同的子类,   

在使用时,只需要传入不同的子类即可.

9.代理模式

        为目标对象(汽车厂, save(),delete()),提供代理对象,  让客户通过代理对象对目标进行访问,

        好处:  不让客户直接与目标对象直接交互

                  代理对象可以为目标对象添加额外的扩展功能.  而且不需要修改目标对象

        9.1静态代理

                静态代理,一个代理类只能为某个接口/抽象类的子类进行代理,

                如果需要为其他接口/抽象类的子类进行代理,那么就需要重新创建一个代理类.

        9.2动态代理

                动态代理解决了一个代理类只能代理某个接口的子类,

                可以为目标类动态生成代理对象,可以为任何目标类实现代理

                动态代理有两种实现方式:

                jdk代理:

                        底层是通过反射机制实现, 要求目标类必须实现一个接口

package com.ffyc.javapro.oop.design.proxy.dtProxy;


public class PhoneFactory implements SellPhone {
    @Override
    public void sellPhone() {
        System.out.println("手机厂卖手机");
    }
}
/*
    汽车厂
 */
public class CarFactoryImpl implements SellCar {

    @Override
    public void sellCar() {
        System.out.println("汽车厂卖汽车");
    }

}
/*
    代理对象的生成器类
 */
public class DynamicProxy implements InvocationHandler {

     Object object;//真实对象,接收任何的目标类对象

    public DynamicProxy(Object object) {
        this.object = object;
    }

    /*
           在代理类中调用目标类中的具体方法,
           动态的将代理动态对象,目标类中要调用的方法,及方法中的参数传递过来
           Method method  就是动态获取的真正要执行的方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("之前开启事务");
        method.invoke(object);//想起反射机制 ,method表示要真正执行的方法
        System.out.println("之后提交事务");
        return proxy;
    }

    /*
       使用反射机制,生成代理对象的
     */
    public Object getProxy(){                                               //获取目标类的接口
          return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }

}
/*
   抽象操作定义 卖东西
 */
public interface SellCar {

      void sellCar();


}

public interface SellPhone {

    void sellPhone();

}
package com.ffyc.javapro.oop.design.proxy.dtProxy;



public class Test {

    public static void main(String[] args) {

          CarFactoryImpl carFactory = new CarFactoryImpl();//创建真实主题
          DynamicProxy dtproxy =  new DynamicProxy(carFactory);//创建代理对象生成器
          //这才是真正的创建动态代理对象   获取目标类所实现的接口
          SellCar carfactory =    (SellCar)dtproxy.getProxy();
          carfactory.sellCar();//使用代理对象调用接口中的方法,获取当前调用的方法,最终调用invoke方法


          PhoneFactory phoneFactory = new PhoneFactory();
          DynamicProxy dynamicProxy = new DynamicProxy(phoneFactory);
           SellPhone  sellPhone = (SellPhone) dynamicProxy.getProxy();
           sellPhone.sellPhone();

    }
}

                spring中的cglib代理:

                        底层采用字节码生成技术,动态为目标类生成一个子类,在调用目标类方法,采用方法

                拦截技术,在调用方法之前和之后添加额外扩展功能,   目标类可以不实现接口

package com.ffyc.javapro.oop.design.proxy.cglibproxy;

//具体主题
public  class CarFactoryImpl {

	 
	    public  void sell() {
	        System.out.println("汽车厂卖汽车");
	    }


}
package com.ffyc.javapro.oop.design.proxy.cglibproxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


/*
 * 动态代理生成器类
 */
public class CGLibProxy implements MethodInterceptor {
    
	    private Enhancer enhancer = new Enhancer();
	    
	    public Object getProxy(Class<?> clazz){  
	        enhancer.setSuperclass(clazz);  
	        enhancer.setCallback(this);  
	        return enhancer.create();  
	    }  
	    /*
	     * 拦截所有目标类方法的调用 
	     * 参数: 
	     * obj  目标实例对象 
	     * method 目标方法的反射对象 
	     * args 方法的参数 
	     * proxy 代理类的实例 
	     */
	    public Object intercept(Object obj, Method method, Object[] args,  
	            MethodProxy proxy) throws Throwable {
	        //代理类调用父类的方法  
	        System.out.println("开始事务");  
	        Object obj1 = proxy.invokeSuper(obj, args);  
	        System.out.println("关闭事务");  
	        return obj1;  
	    }
}
package com.ffyc.javapro.oop.design.proxy.cglibproxy;


public class Test {

	 public static void main(String[] args) {
		  CGLibProxy proxy = new CGLibProxy();
		  CarFactoryImpl carFactory = (CarFactoryImpl) proxy.getProxy(CarFactoryImpl.class);
		  carFactory.sell();
	}
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐