常用的设计模式

设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。1995 年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了 23 种设计模式,从此树立了软件设计模式领域的里程碑,人称「GoF设计模式」。这 23 种设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性,以及类的关联关系和组合关系的充分理解。设计模式并不是 Java 的专利,它同样适用于 C++、C#、JavaScript 等其它面向对象的编程语言。设计模式总原则:开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。
单例模式
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。
单例模式的要点有三个:

  1. 单例类只能有一个实例;
  2. 单例类必须自己创建自己的唯一实例;
  3. 单例类必须给所有其他对象提供这一实例。
    对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;如在Windows中就只能打开一个任务管理器。
    从具体实现角度来说,就是以下三点:
  4. 单例模式的类只提供私有的构造函数
  5. 单例类定义中含有一个该类的静态私有对象
  6. 该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。(公共的访问方式)
    单例模式的实现:
    ①懒汉式(线程不安全),是常用的形式
//懒汉式单例:在第一次调用的时候实例化自己
public class Singleton {
	//1、私有的构造函数
	private Singleton(){};
	//2、该类的静态私有对象
	private static Singleton single=null;
	//3、公共静态方法,供访问
	public static Singleton getInstance(){
		if(single==null){
			single=new Singleton();
		}
		return single;
	}
}

②饿汉式(线程安全)

//饿汉式单例,在类初始化时,已经自行实例化
public class Singleton1 {
	//1、私有构造函数
	private Singleton1(){};
	//2、通过静态最终变量实例化
	private static final Singleton1 single=new Singleton1();
	//3、公共静态方法
	public static Singleton1 getInstance(){
		return single;
	}
}

当然线程不安全的懒汉式如果要保证其安全问题,后续我们可以通过同步,枚举…方式进行处理。
工厂模式与代理模式
工厂模式:
⑴还没有工厂时代:假如还没有工业革命,如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用。
⑵**简单工厂模式(掌握):**后来出现工业革命。用户不用去创建宝马车。因为客户有一个工厂来帮他创建宝马.想要什么车,这个工厂就可以建。比如想要320i系列车。工厂就创建这个系列的车。即工厂可以创建产品。
简单工厂模式的组成:
① 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
② 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
③ 具体产品角色:工厂类所创建的对象就是此角色的实例。在Java中由一个具体类实现。
⑶工厂方法模式时代(了解):为了满足客户,宝马车系列越来越多,如320i,523i,30li等系列一个工厂无法创建所有的宝马系列。于是由单独分出来多个具体的工厂。每个具体工厂创建一种系列。即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象。你需要指定某个具体的工厂才能生产车出来。
⑷抽象工厂模式时代(了解):随着客户的要求越来越高,宝马车必须配置空调。于是这个工厂开始生产宝马车和需要的空调。
静态代理
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
组成:
①抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
②真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
③代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
静态代理模式的组成:
 真实角色与代理角色实现相同的接口
 代理角色持有真实角色的引用
 代理行为
代理模式的主要优点有:

  1. 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  2. 代理对象可以扩展目标对象的功能;
  3. 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
  4. 因此,面向对象这种思维是任何人都需要学习、任何人都需要掌握的。
public interface HttpApi {
    String get(String url);
}

public class RealModule implements HttpApi {
     @Override
     public String get(String url) {
         return "result";
     }
}

public class Proxy implements HttpApi {
    private HttpApi target;

    Proxy(HttpApi target) {
        this.target = target;
    }

    @Override
    public String get(String url) {
        // 扩展的功能
        Log.i("http-statistic", url);
        // 访问基础对象
        return target.get(url);
    }
}

内部类
理解内部类的作用
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
 内部类的共性:
 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。
 内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。

成员内部类
成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:
a)内部类的基本结构
内部类其实严重破坏了良好的代码结构,但为什么还要使用内部类呢?
因为内部类可以随意使用外部类的成员变量(包括private)而不用生成外部类的对象,这也是内部类的唯一优点
b)内部类中的变量访问形式
内部类在没有同名成员变量和局部变量的情况下,内部类会直接访问外部类的成员变量;若有同名情况时,直接访问会导致内部类中的局部变量将外部类的成员变量覆盖,访问内部类本身的成员变量可用this.属性名,访问外部类的成员变量需要使用Out.this.属性名
理解内部类的作用
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
 内部类的共性:
 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。
 内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。
2. 成员内部类
成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:
a)内部类的基本结构
内部类其实严重破坏了良好的代码结构,但为什么还要使用内部类呢?
因为内部类可以随意使用外部类的成员变量(包括private)而不用生成外部类的对象,这也是内部类的唯一优点
b)内部类中的变量访问形式
内部类在没有同名成员变量和局部变量的情况下,内部类会直接访问外部类的成员变量;若有同名情况时,直接访问会导致内部类中的局部变量将外部类的成员变量覆盖,访问内部类本身的成员变量可用this.属性名,访问外部类的成员变量需要使用Out.this.属性名
c)创建内部类实例

Out.Inner inner=new Out().new Inner();
或
Out out=new Out()
Out.Inner inner=out.new Inner()

d)私有内部类
如果一个内部类只希望被外部类中的方法操作,那么可以使用private声明内部类,此时我们必须在Out类里面生成In类的对象进行操作,而无法再使用Out.In in = new Out().new In() 生成内部类的对象
也就是说,此时的内部类只有外部类可控制如同是,我的心脏只能由我的身体控制,其他人无法直接访问它
静态内部类
如果用static 将内部类静态化,那么内部类就只能访问外部类的静态成员变量,不能直接访问外部类的实例变量、实例方法,只有通过对象引用才能访问。

其次,因为内部类被静态化,因此Out.In可以当做一个整体看,可以直接new 出内部类的对象(静态内部类不通过外部类实例进行创建对象)

局部内部类
将内部类移到了外部类的方法中,然后在外部类的方法中再生成一个内部类对象去调用内部类方法。局部内部类和成员内部类的区别在于局部内部类的访问仅限于方法内
如果此时我们需要往外部类的方法中传入参数,那么外部类的方法形参必须使用final定义
至于final在这里并没有特殊含义,只是一种表示形式而已
局部内部类:像局部变量一样,不能被public, protected, private和static修饰。
jdk1.8 +可以不加 final
匿名内部类
匿名内部类:定义类的最终目的是创建一个类的实例,但是如果某个类的实例只是用一次,则可以将类的定义与类的创建,放到与一起完成,或者说在定义类的同时就创建一个类 , 以这种方法定义的没有名字的类成为匿名内部类。
声明和构造匿名内部类的一般格式如下:
new ClassOrInterfaceName(){
/类体/
}

①匿名内部类可以继承一个类或实现一个接口,这里的ClassOrInterfaceName是匿名内部类所继承的类名或实现的接口名。但匿名内部类不能同时实现一个接口和继承一个类,也不能实现多个接口。如果实现了一个接口,该类是Object类的直接子类,匿名类继承一个类或实现一个接口,不需要extends和implements关键字。
②由于匿名内部类没有名称,所以类体中不能定义构造方法,由于不知道类名也不能使用关键字来创建该类的实例。实际上匿名内部类的定义、构造、和第一次使用都发生在同样一个地方。此外,上式是一个表达式,返回的是一个对象的引用,所以可以直接使用或将其复制给一个对象变量,如:
TypeName obj=new Name(){
/此处为类体/
}

同样,也可以将构造的对象作为调用的参数。例:
someMethod(new Name(){
/此处为类体/
});

  • 局部内部类:像局部变量一样,不能被public, protected, private和static修饰。Jdk1.7中只能访问方法中定义的final类型的局部变量。

匿名内部类:匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。匿名内部类隐式地继承了一个父类或者实现了一个接口。匿名内部类使用得比较多,通常是作为一个方法参数。
使用内部类的原因主要有以下四点:
 ①每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整
 ②方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
 ③方便编写事件驱动程序
 ④方便编写线程代码
第一点是最重要的原因之一,内部类的存在使得Java的多继承机制变得更加完善

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值