java设计模式之美

设计模式的概述

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。我们在项目中使用设计模式实现一些功能,使我们的代码更加的简洁。更加的高效。

设计模式的分类

设计模式可以分为23类

  • 创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。

  • 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

  • 行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)、访问者模式。

设计模式的原则

开闭原则

此原则是由Bertrand Meyer提出的。开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。

里氏代换原则

里氏代换原则是由Barbara Liskov提出的。如果调用的是父类的话,那么换成子类也完全可以运行。

里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。例如:我喜欢动物,那我一定喜欢狗,因为狗是动物的子类;但是我喜欢狗,不能据此断定我喜欢动物,因为我并不喜欢老鼠,虽然它也是动物。

里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

依赖倒转原则

抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。

接口隔离原则

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意:降低依赖,降低耦合。

根据接口隔离原则,当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。这里的“接口”往往有两种不同的含义:一种是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象;另外一种是指某种语言具体的“接口”定义,有严格的定义和结构

单一职责原则

单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

单一职责原则告诉我们:一个类不能太“累”!在软件系统中,一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小,而且一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中,即将不同的变化原因封装在不同的类中,如果多个职责总是同时发生改变则可将它们封装在同一类中。

单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实践经验。

迪米特法则

迪米特法则(Law of Demeter)又叫作最少知道原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。

迪米特法则要求我们在设计系统时,应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度。

单例模式

单例模式是我们在平常中常用到的一种设计模式之一,它能保证在我们的程序中,只能有一个对象存在。

我们在开发中比如一个创建起来很大的类,就可以使用单例模式,降低内存的开销。同时,如果我们希望某一个类只有一个对象被创建,就可以使用单例模式。

package com.Singleton;
//单例模式

class Singleton{
    //创建当前类的属性声明,
    private static Singleton singleton = null;
    //把构造方法私有化,在外部不能通过构造函数创造对象。
    private Singleton(){

    }
    //提供一个静态方法,进行实例化对象。
    public static synchronized Singleton getInstance(){
        //判断当前对象是否初始化。
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }

}

public class SingleMode {

    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        //通过判断两个对象的地址是否一样
        if(instance == instance2){
            System.out.println("一样");
        }else{
            System.out.println("不一样");
        }
    }
}
  • 我们在创建对象的时候,都是程序自动的调用构造函数,因此在这里我们把构造函数私有化,这样在外部就不能通过new关键字进行创建对象。

  • 我们把构造函数私有化,不能再外部进行创建,不能得到类的对象,这就需要在类的内部定义一个静态方法,而这个静态方法返回当前类的对象,这样在外部就能通过访问类的静态方法得到类的对象,当然,在调用静态方法前,先判断当前类的对象是否创建。

  • 在类中定义一个当前类的对象实例。

  • 如果把当前类放在多线程环境中,根据线程执行机制,可能创建多个对象实例,所以我们在静态方法上通过synchronized关键字上锁来解决。

工厂模式

工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。

比如我们在开发中需要使用铅笔对象或者钢笔对象来进行绘制图像。而我们可以使用工厂模式来实现不同对象的创建。

  1. 先创建一个铅笔和钢笔共同的接口。

    /**
     * 创建公共的接口笔类。
     * @author Administrator
     *
     */
    interface Pen{
        public void write();
    }
    
  2. 创建铅笔类和钢笔类,实现笔接口类。

    /**
     * 
     * @author li
     * 定义铅笔的类事项Pen类。
     */
    class Pencil implements Pen{
    
        public void write() {
            System.out.println("铅笔写字");
        }
    }
    /**
     * 
     * @author li
     *定义钢笔的类事项Pen类。
     */
    class FountainPen implements Pen{
    
        public void write() {
            System.out.println("钢笔写字");
        }
    }
    
  3. 创建工厂类

    /**
     * 
     * @author Administrator
     *定义工程类,通过工程类创建不同的对象。
     */
    class PenFactory {  
    
        public static Pen producePencil(){  
            return new Pencil();  
        }  
    
        public static Pen produceFountainPen(){  
            return new FountainPen();  
        }  
    }
    
  4. 测试类

    /**
     * 
     * @author Administrator
     *测试类
     */
    public class FactoryMethod {
    
        public static void main(String[] args) {
            //通过工厂类的produce方法创建不同的对象
            Pen pencil = PenFactory.producePencil();
            pencil.write();
        }
    
    }
    
  5. 结果

    铅笔写字
    钢笔写字
    

  • 我们通过创建工厂类,根据调用不同的静态方法,返回不同的对象。这样我么用到不同的类,就不用使用new关键字进行创建。并把类进行统一的管理。

抽象工厂模式

上面的工厂方法模式其实有一个问题,如果我们又新增了一个毛笔类,这是我们就要修改工厂类,在工厂类里面添加一个静态方法。就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则。

而解决的方法就是使用抽象工厂模式,把工厂类定义成一个接口,然后给每一个对象创建一个单独的工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

  1. 先创建一个铅笔和钢笔共同的接口。

    /**
     * 创建公共的接口笔类。
     * @author Administrator
     *
     */
    interface Pen{
        public void write();
    }
    
  2. 创建铅笔类和钢笔类,实现笔接口类。

    /**
     * 
     * @author li
     * 定义铅笔的类事项Pen类。
     */
    class Pencil implements Pen{
    
        public void write() {
            System.out.println("铅笔写字");
        }
    }
    /**
     * 
     * @author li
     *定义钢笔的类事项Pen类。
     */
    class FountainPen implements Pen{
    
        public void write() {
            System.out.println("钢笔写字");
        }
    }
    
  3. 创建工厂类的接口

    /**
     * 
     * @author Administrator
     *定义一个工厂的接口类
     */
    interface Provider {  
        public Pen produce();  
    }  
    
  4. 根据不同的类,创建不同的工厂类,实现工厂类接口

    /**
     * 
     * @author Administrator
     *分别创建铅笔和钢笔的工厂类。
     */
    class PencilFactory implements Provider {
    
        public Pen produce() {
            return new Pencil();
        }  
    
    }  
    
    class FountainPenFactory implements Provider{
    
        public Pen produce() {
            return new FountainPen();
        }  
    }
    
  5. 测试类

    /**
     * 
     * @author Administrator
     *测试类
     */
    public class FactoryMethod2 {
    
        public static void main(String[] args) {
            //通过不同的工厂类的produce方法创建不同的对象
            PencilFactory factory = new PencilFactory();
            Pen pencil = factory.produce();
            pencil.write();
        }
    
    }
    
  6. 结果

    铅笔写字
    

当我们使用抽象工厂模式,如果你现在想增加一个功能,是要实现pen接口,并创建一个实现Provider接口的工厂类,就OK了,无需去改动现成的代码。这样做,拓展性较好!

适配器模式

我们在这里讲的适配器模式,是接口适配模式,也称之为缺省适配器模式。

有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,但是并不是所有的方法都是我们需要的,有时只需要某一些方法,这时,我们就可以使用接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口中所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。

  1. 定义一个接口,里边有所有的方法。

    //定义所有的抽象方法。
    interface Sourceable {  
    
        public void method1();  
        public void method2();  
    } 
    
  2. 借助于一个抽象类,该抽象类实现了接口中所有的方法

    //定义一个抽象类,实现接口里面的所有方法。
    abstract class Wrapper implements Sourceable{  
    
        public void method1(){}  
        public void method2(){}  
    }  
    
  3. 我们不和原始的接口打交道,只和抽象类取得联系,写一个类,继承该抽象类,重写我们需要的方法。

    //定义适配类。只对method1这个方法感兴趣。
    class BaseAdapter1 extends Wrapper {  
        public void method1(){  
            System.out.println("I like method1");  
        }  
    }  
    
    //定义适配类。只对method2这个方法感兴趣。
    class BaseAdapter2 extends Wrapper {  
        public void method2(){  
            System.out.println("I like method2");  
        }  
    } 
    
  4. 测试类

    public class AdapterTest {  
    
        public static void main(String[] args) {  
            Sourceable source1 = new BaseAdapter1();  
            Sourceable source2 = new BaseAdapter2();  
    
            source1.method1();  
            source1.method2();  
            source2.method1();  
            source2.method2();  
        }  
    }
    
  5. 结果

    I like method1
    I like method2
    

  • 通过定义一个抽象类实现接口的所有的方法,这时我们就可以不用和原始的接口打交道,只和抽象类取得联系,写一个类,继承该抽象类,重写我们需要的方法。

你可能感兴趣的:(Java)