オブジェクト向けの角度で抽象クラスとインタフェースを分析する

25951 ワード

対象思想
オブジェクト向けプログラミングOOP(Object Oriented Programming)パッケージ、継承、マルチステートの3つの特徴があります.
カプセル化(英語: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("    " + "
"
); sb.append(" :" + location.getErrorCode() + "
"
); sb.append(" :" + location.getErrorInfo() + "
"
); sb.append(" :" + location.getLocationDetail() + "
"
); // , 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       
    }
}

インタフェース向けプログラミング
理想的なプログラミングは一般的に「高集約,低結合」と概括されています.
内聚とは専任者が専任し、専門的な類が専門的なことをすることを指す.オブジェクト向けプログラミングでは,オブジェクト自体が集約され,自分のデータを保管し,自分の操作を完了し,外部に対して自分の状態と行為を示す.1つのオブジェクトは往々にしてすべてのことをすることができず、他のオブジェクトと連絡を取り、1つのオブジェクトと別のオブジェクトは依存関係、すなわち結合を生じなければならない.
我々はプロジェクト開発の過程で、一般的に依存逆置き原則(Dependence Inversion Principle,DIP)とは、コード構造を設計する際に、呼び出し元が被呼び出し元に依存すべきではなく、両方が抽象に依存すべきであることを意味する.例えば、私は印刷店に行って印刷します.印刷店が白黒プリンタしかない場合、カラーを印刷したい場合は、印刷店を変えたり、印刷店にカラープリンタを追加したりすることしかできません.この現象を呼び出し側依存被呼び出し側と言います.依存逆置きの原則を使用して、私の印刷店はその抽象、つまりプリンタに依存して、私は1つのプリンタをインタフェースとして抽象して、印刷方法の中でプリンタの実現クラスに入るだけで各種のタイプの印刷を実現することができます.
バックグラウンドに依存することにより、クラスとクラス間の結合性を低減し、システムの安定性を向上させ、コードの可読性とメンテナンス性を向上させ、プログラムの修正によるリスクを低減することができる.依存逆置きの原則はインタフェース向けのプログラミングの一つの体現である.
オブジェクト向けプログラミングは実は高集約に偏っており、インタフェース向けは低結合向けインタフェースに体現されており、抽象向けを意味し、哲学の範疇としては規定性が抽象と呼ばれることは少なく、規定性は具体と呼ばれることが多い.インタフェースと抽象クラスは、プログラムの典型的な「抽象」の形式であるため、インタフェース向けのプログラミングの目的はデカップリングであり、プログラミングの柔軟性を保証することである.
参考runoob:カプセル化、継承、マルチステート年に分からない高度な用語--依存逆置き•制御反転•依存注入•インタフェース向けプログラミング