以面向对象的角度分析抽象类和接口

面向对象思想

面向对象编程即 OOP(Object Oriented Programming)
它有三大特征 :封装、继承、多态

封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
多态是同一个行为具有多个不同表现形式或形态的能力。

面向对象思想相当于对万物的一个抽象,抽象具体体现在接口和抽象类

抽象类和接口

1.首先在定义上:
接口可以理解为特殊的抽象类;
抽象类和接口都是一个不完整的类,都没办法直接使用;
抽象类中既可以定义抽象方法、非抽象方法,也可以定义成员属性;
抽象类中的方法可以有方法体也可以没有方法体,只有方法名;
接口只可以定义方法名,接口中也可以定义属性,但是属性一定是public static final类型的。

另外,java 是单继承的,接口实际上是对单继承的补充。C++是有多继承的,为了能实现类的多继承,java中可以用接口来实现多继承的机制

2.在语义上:
抽象类它针对的是行为和属性上进行抽象;
接口针对的是扩展的功能或能力,可以有这种能力也可以没有
只要实现了接口就代表有这个能力

3.现实使用的例子:
工作中的项目里将公共的方法向上抽取,成基类,比如BaseActivity,这个基类一般定义成抽象类,公共的功能向上抽取,写在基类BaseActivity中,需要不同页面实现的功能,需要定义成抽象方法,然后继承后重写,各自实现。比如各自页面的layout,如下面的例子

public abstract class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutRes());
    }
   	//不同页面布局,需要定义成抽象方法,然后继承后重写
    protected abstract int getLayoutRes();
    protected abstract void initView();
}
public class TestActivity extends BaseActivity {
    

    @Override
    protected int getLayoutRes() {
        return R.layout.activity_test;
    }

    @Override
    protected void initView() {
        //todo 初始化view
    }
}

下面的例子讲解接口
接口主要表现在扩展能力上,比如地图定位并不是每个activty都使用,所以定义成一个接口,需要的时候来实现

//定义定位接口
interface LocationInterface {
	//初始化定位sdk
    void initLocation();
    //开始定位
    void startLocation();
}

抽象一个LocationActivity 来做定位初始化,将定位结果回调给继承它的子类Activity

public abstract class LocationActivity extends BaseActivity implements LocationInterface {

    private AMapLocationClient locationClient;

    @Override
    public void initLocation() {
        //初始化client
        locationClient = new AMapLocationClient(this.getApplicationContext());
        AMapLocationClientOption locationOption = getDefaultOption();
        //设置定位参数
        locationClient.setLocationOption(locationOption);
        // 设置定位监听
        locationClient.setLocationListener(locationListener);
    }

    @Override
    public void startLocation() {
        // 启动定位
        if (locationClient == null)
            return;
        locationClient.startLocation();
    }

    /**
     * 默认的定位参数
     */
    private AMapLocationClientOption getDefaultOption() {
        AMapLocationClientOption mOption = new AMapLocationClientOption();
        mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
        mOption.setGpsFirst(false);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭
        mOption.setHttpTimeOut(30000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
        mOption.setInterval(2000);//可选,设置定位间隔。默认为2秒
        mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true
        mOption.setOnceLocation(true);//可选,设置是否单次定位。默认是false
        mOption.setOnceLocationLatest(false);//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
        AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
        mOption.setSensorEnable(false);//可选,设置是否使用传感器。默认是false
        mOption.setWifiScan(true); //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差
        mOption.setLocationCacheEnable(true); //可选,设置是否使用缓存定位,默认为true
        mOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT);//可选,设置逆地理信息的语言,默认值为默认语言(根据所在地区选择语言)
        return mOption;
    }

    /**
     * 定位监听
     */
    AMapLocationListener locationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged(AMapLocation location) {
            if (null != location) {

                StringBuffer sb = new StringBuffer();
//                //errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明
                if (location.getErrorCode() == 0) {
                    //区域码
                    String adCode = location.getAdCode();

                    String province = location.getProvince();

                    String city = location.getCity();
                    String district = location.getDistrict();
                    updateAddress(adCode, province, city, district);
                } else {
                    //定位失败
                    sb.append("定位失败" + "\n");
                    sb.append("错误码:" + location.getErrorCode() + "\n");
                    sb.append("错误信息:" + location.getErrorInfo() + "\n");
                    sb.append("错误描述:" + location.getLocationDetail() + "\n");
                    //解析定位结果,
                    String result = sb.toString();
                    LogUtil.e(result);
                }
            } else {
                LogUtil.e("定位失败,loc is null");
            }
        }
    };

    protected abstract void updateAddress(String adCode, String province, String city, String district);

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != locationClient) {
            /**
             * 如果AMapLocationClient是在当前Activity实例化的,
             * 在Activity的onDestroy中一定要执行AMapLocationClient的onDestroy
             */
            locationClient.onDestroy();
            locationClient = null;
        }
    }
}

TestActivity 继承LocationActivity ,TestActivity 就具备获取定位的功能,如果不想让其拥有定位功能可以继续继承BaseActivity

public class TestActivity extends LocationActivity {


    @Override
    protected int getLayoutRes() {
        return R.layout.activity_test;
    }

    @Override
    protected void initView() {
        //todo 初始化view


        //举例子,在此处初始化和开始定位
        initLocation();
        startLocation();
    }

    @Override
    protected void updateAddress(String adCode, String province, String city, String district) {
        //todo 回调定位信息
    }
}

面向接口编程

我们对理想的编程通常概括为“高内聚,低耦合”,

内聚指的是专人专职,专门的类做专门的事;
在面向对象编程中,对象自身是内聚的,是保管好自己的数据,完成好自己的操作的,而对外界呈现出自己的状态和行为。一个对象往往不能干所有的事,都要与其它对象产生联系,一个对象和另一个对象产生依赖关系,也就是耦合。

我们在项目开发过程中,一般会用到依赖倒置原则(Dependence Inversion Principle,DIP)是指设计代码结构时,调用方不应该依赖被调用方,二者都应该依赖其抽象。举例来说就是,我去打印店打印,打印店如果只有黑白打印机,而我想打印彩色,这时,只能通过换一家打印店,或者让打印店再添加一台彩色打印机,这种现象就叫做调用方依赖被调用方。使用依赖倒置原则,我的打印店依赖其抽象,也就是打印机,我抽象一个打印机为接口,在打印方法中只需要传入打印机的实现类就能实现各种类型的打印了。

通过依赖倒置,可以减少类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并且能够降低修改程序所造成的风险。
依赖倒置原则就是面向接口编程的一个体现。

面向对象编程其实更偏重于高内聚,面向接口更体现在低耦合
面向接口,就意味着面向抽象,作为哲学范畴而言,规定性少称为抽象,规定性多称为具体。而接口和抽象类,都是程序中的一种典型的“抽象”的形式,所以说面向接口编程目的是解耦,保证编程的灵活性。

参考
runoob:封装、继承、多态
那些年搞不懂的高深术语——依赖倒置•控制反转•依赖注入•面向接口编程

你可能感兴趣的:(java,Android)