1 面向对象
2 设计模式
1 面向对象
1.1 多态
多态是具有表现多种形态的能力特征,在OO中是指,语言具有根据对象的类型以不同方式处理之,特别是重载方法和继承类这种形式的能力。多态被认为是面向对象语言的必备特性。
一个有趣但不严谨的说法是:继承是子类使用父类的方法,而多态则是父类使用子类的方法。一般,我们使用多态是为了避免在父类里大量重载引起代码臃肿且难于维护。
多态的前提是必须有子父类关系或者类实现接口关系,否则无法完成多态。
在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
1.2 重写、重载
override->重写(=覆盖)、overload->重载、polymorphism -> 多态
重写(覆盖)的规则:
- 重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载。
- 重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)
- 重写的方法的返回值必须和被重写的方法的返回一致
- 重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类
- 被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写
- 静态方法不能被重写为非静态的方法(会编译出错)
overload是重载:一般是用于在一个类内实现若干重载的方法,这些方法的名称相同而参数形式不同。
重载的规则:
- 在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);
- 不能通过访问权限、返回类型、抛出的异常进行重载;
- 方法的异常类型和数目不会对重载造成影响;
1.3 代码
public class Parent {
public int a = 1;
public static int b = 1;
public Parent(){
System.out.println("Parent is created");
}
{
System.out.println("parent no static");
}
static{
System.out.println("parent static");
}
protected void method(){
System.out.println("parent method");
}
public void m(){
this.method();
}
}
public class Child extends Parent{
public int a = 2;
public static int b = 2;
public Child(){
System.out.println("child is created");
}
{
System.out.println("child no static");
}
static{
System.out.println("child static");
}
protected void method(){
System.out.println("child method");
}
}
@Test
public void method() {
Parent p = new Child();
Child c = (Child) p;
c.m();
p.m();
System.out.println(p.a+""+p.b);
System.out.println(((Child) p).a+""+((Child) p).b);
System.out.println(c.a+""+c.b);
System.out.println(((Parent)c).a+""+((Parent)c).b);
}
输出结果
parent static
child static
parent no static
Parent is created
child no static
child is created
child method
child method
11
22
22
11
2 常见设计模式
(1)单例设计模式
简单点说,就是一个应用程序中,某个类的实例对象只有一个,不能新创建对象,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。getInstance()的返回值是一个对象的引用,并不是一个新的实例。
public class SingleTon_hungery{
private static final SingleTon_hungery singleton_hungery
= new SingleTon_hungery();
private SingleTon_hungery(){}
public static SingleTon_hungery getInstance(){
return singleton_hungery;
}
}
public class SingleTon_Lazy{
private static final SingleTon_Lazy singleton_lazy
= new SingleTon_Lazy();
private SingleTon_Lazy(){}
public static SingleTon_Lazy getInstance(){
if(singleton_lazy ==null){
synchronized(SingleTon_Lazy .class){
if(singleton_lazy == null){
singleton_lazy = new SingleTon_Lazy();
}
}
}
}
}
(2)观察者模式
对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。
https://www.cnblogs.com/luohanguo/p/7825656.html
(3)装饰者模式
对已有的业务逻辑进一步的封装,使其增加额外的功能,如Java中的IO流就使用了装饰者模式,用户在使用的时候,可以任意组装,达到自己想要的效果。
https://www.cnblogs.com/chenxing818/p/4705919.html
(4)适配器模式
适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配。例如常见的变压器、转换器之类。
适配器模式有两种:类适配器、对象适配器、接口适配器。
前二者在实现上有些许区别,作用一样,第三个接口适配器差别较大。
https://www.cnblogs.com/V1haoge/p/6479118.html
https://blog.csdn.net/YuenBin128/article/details/80314079
(5)工厂模式
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
优点:
(1)利用工厂的工厂方法类去创建具体的产品对象,隐藏了具体产品对象的创建细节,只需要关心具体产品对应的具体工厂;
(2)遵守开闭原则。加入新的产品类时,只需要同时加入工厂类就可以实现扩展,无需修改原来的代码。
缺点:
随着产品种类的数量的增长,工厂类也会随之增加,将不利于系统的维护,增加系统编译和运行的开销。
适用场景:
(1)对于某个产品,调用者清楚地知道应该使用哪个具体的工厂来服务,实例化该具体工厂,生产出具体的产品来;
(2)只是需要一种产品,而不想知道也不需要知道工厂是如何生产出来的,自需要知道具体对应的工厂就行。
https://blog.csdn.net/pnjlc/article/details/52711486
(6)代理模式(proxy)
代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。
代理模式的实现
代理模式可以有两种实现的方式,一种是静态代理类,另一种是各大框架都喜欢的动态代理。
(1)静态代理
代理模式的特点:代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。
(2)动态代理
动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。
其步骤如下:
- 编写一个委托类的接口,即静态代理的(Subject接口)
- 实现一个真正的委托类,即静态代理的(RealSubject类)
- 创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法
- 在测试类中,生成动态代理的对象