[转载] 面向对象编程的6大原则

原文: http://blog.csdn.net/bboyfeiyu/article/details/43928463

概述

在工作初期,我们可能会经常会有这样的感觉,自己的代码接口设计混乱、代码耦合较为严重、一个类的代码过多等等,自己回头看的时候都觉得汗颜。再看那些知名的开源库,它们大多有着整洁的代码、清晰简单的接口、职责单一的类,这个时候我们通常会捶胸顿足而感叹:什么时候老夫才能写出这样的代码!

在做开发的这些年中,我渐渐的感觉到,其实国内的一些初、中级工程师写的东西不规范或者说不够清晰的原因是缺乏一些指导原则。他们手中挥舞着面向对象的大旗,写出来的东西却充斥着面向过程的气味。也许是他们不知道有这些原则,也许是他们知道但是不能很好运用到实际代码中,亦或是他们没有在实战项目中体会到这些原则能够带来的优点,以至于他们对这些原则并没有足够的重视。

今天,我们就是以剖析优秀的Android网络框架Volley为例来学习这六大面向对象的基本原则,体会它们带来的强大能量。

在此之前,有一点需要大家知道,熟悉这些原则不会让你写出优秀的代码,只是为你的优秀代码之路铺上了一层栅栏,在这些原则的指导下你才能避免陷入一些常见的代码泥沼,从而让你专心写出优秀的东西。另外,我是个新人,以下只是我个人的观点。如果你觉得还行,可以顶个帖支持一下;如果你觉得它不行,还请分享你的经验。

Volley相关资料

单一职责原则 ( Single Responsibility Principle )

简述

单一职责原则的英文名称是Single Responsibility Principle,简称是SRP,简单来说一个类只做一件事。这个设计原则备受争议却又及其重要的原则。只要你想和别人争执、怄气或者是吵架,这个原则是屡试不爽的。因为单一职责的划分界限并不是如马路上的行车道那么清晰,很多时候都是需要靠个人经验来界定。当然最大的问题就是对职责的定义,什么是类的职责,以及怎么划分类的职责。

试想一下,如果你遵守了这个原则,那么你的类就会划分得很细,每个类都有自己的职责。恩,这不就是高内聚、低耦合么! 当然,如何界定类的职责这需要你的个人经验了。

示例

在Volley中,我觉得很能够体现SRP原则的就是HttpStack这个类族了。HttpStack定义了一个执行网络请求的接口,代码如下 :

/**
 * An HTTP stack abstraction.
 */
public interface HttpStack {
    /**
     * 执行Http请求,并且返回一个HttpResponse
     */
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
        throws IOException, AuthFailureError;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

可以看到,HttpStack只有一个函数,清晰明了,它的职责就是执行网络请求并且返回一个Response。它的职责很单一,这样在需要修改执行网络请求的相关代码时我们只需要修改实现HttpStack接口的类,而不会影响其它的类的代码。如果某个类的职责包含有执行网络请求、解析网络请求、进行gzip压缩、封装请求参数等等,那么在你修改某处代码时你就必须谨慎,以免修改的代码影响了其它的功能。但是当职责单一的时候,你修改的代码能够基本上不影响其它的功能。这就在一定程度上保证了代码的可维护性。注意,单一职责原则并不是说一个类只有一个函数,而是说这个类中的函数所做的工作必须要是高度相关的,也就是高内聚。HttpStack抽象了执行网络请求的具体过程,接口简单清晰,也便于扩展。

我们知道,Api 9以下使用HttpClient执行网络请求会好一些,api 9及其以上则建议使用HttpURLConnection。这就需要执行网络请求的具体实现能够可扩展、可替换,因此我们对于执行网络请求这个功能必须要抽象出来,HttpStack就是这个职责的抽象。

优点

  • 类的复杂性降低,实现什么职责都有清晰明确的定义;
  • 可读性提高,复杂性降低,那当然可读性提高了;
  • 可维护性提高,可读性提高,那当然更容易维护了;
  • 变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。

里氏替换原则 ( Liskov Substitution Principle)

简述

面向对象的语言的三大特点是继承、封装、多态,里氏替换原则就是依赖于继承、多态这两大特性。里氏替换原则简单来说就是所有引用基类的地方必须能透明地使用其子类的对象。通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

示例

还是以HttpStack为例,Volley定义了HttpStack来表示执行网络请求这个抽象概念。在执行网络请求时,我们只需要定义一个HttpStack对象,然后调用performRequest即可。至于HttpStack的具体实现由更高层的调用者给出。示例如下 :


    public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
        File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);

        String userAgent = "volley/0";
        // 代码省略
        // 1、构造HttpStack对象
        if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                stack = new HurlStack();
            } else {
                // Prior to Gingerbread, HttpUrlConnection was unreliable.
                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
            }
        }
        // 2、将HttpStack对象传递给Network对象
        Network network = new BasicNetwork(stack);
        // 3、将network对象传递给网络请求队列
        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        queue.start();

        return queue;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

BasicNetwork的代码如下:

/**
 * A network performing Volley requests over an {@link HttpStack}.
 */
public class BasicNetwork implements Network {
    // HttpStack抽象对象
    protected final HttpStack mHttpStack;

    protected final ByteArrayPool mPool;

    public BasicNetwork(HttpStack httpStack) {

        this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
    }

    public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
        mHttpStack = httpStack;
        mPool = pool;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

上述代码中,BasicNetwork构造函数依赖的是HttpStack抽象接口,任何实现了HttpStack接口的类型都可以作为参数传递给BasicNetwork用以执行网络请求。这就是所谓的里氏替换原则,任何父类出现的地方子类都可以出现,这不就保证了可扩展性吗?! 此时,用手撑着你的小脑门作思考状… 任何实现HttpStack接口的类的对象都可以传递给BasicNetwork实现网络请求的功能,这样Volley执行网络请求的方法就有很多种可能性,而不是只有HttpClient和HttpURLConnection。

喔,原来是这样!此时我们放下装逼的模样,呈现一副若有所得的样子。细想一下,框架可不就是这样吗? 框架不就是定义一系列相关的逻辑骨架与抽象,使得用户可以将自己的实现传递进给框架,从而实现变化万千的功能。

优点

  • 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
  • 提高代码的重用性;
  • 提高代码的可扩展性,实现父类的方法就可以“为所欲为”了,很多开源框架的扩展接口都是通过继承父类来完成的;
  • 提高产品或项目的开放性。

缺点

  • 继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;
  • 降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;
  • 增强了耦合性。当父类的常量、变量和方法被修改时,必需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的结果——大片的代码需要重构。

依赖倒置原则 (Dependence Inversion Principle)

简述

依赖倒置原则这个名字看着有点不好理解,“依赖”还要“倒置”,这到底是什么意思? 
依赖倒置原则的几个关键点如下:

  • 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
  • 抽象不应该依赖细节;
  • 细节应该依赖抽象。

在Java语言中,抽象就是指接口或抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或继承抽象类而产生的类就是细节,其特点就是可以直接被实例化,也就是可以加上一个关键字 new 产生一个对象。依赖倒置原则在 Java 语言中的表现就是:模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。软件先驱们总是喜欢将一些理论定义得很抽象,弄得神不楞登的,其实就是一句话:面向接口编程,或者说是面向抽象编程,这里的抽象指的是接口或者抽象类。面向接口编程是面向对象精髓之一。

示例

采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。 
第二章节中的BasicNetwork实现类依赖于HttpStack接口( 抽象 ),而不依赖于HttpClientStack与HurlStack实现类 ( 细节 ),这就是典型的依赖倒置原则的体现。加入BasicNetwork直接依赖了HttpClientStack,那么HurlStack就不能传递给了,除非HurlStack继承自HttpClientStack。但这么设计明显不符合逻辑,HurlStack与HttpClientStack并没有任何的is-a的关系,而且即使有也不能这么设计,因为HttpClientStack是一个具体类而不是抽象,如果HttpClientStack作为BasicNetwork构造函数的参数,那么以为这后续的扩展都需要继承自HttpClientStack。这简直是一件不可忍受的事了!

优点

  • 可扩展性好;
  • 耦合度低;

开闭原则 ( Open-Close Principle )

简述

开闭原则是 Java 世界里最基础的设计原则,它指导我们如何建立一个稳定的、灵活的系统。开闭原则的定义是 : 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误。因此当软件需要变化时,我们应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现。

示例

在软件开发过程中,永远不变的就是变化。开闭原则是使我们的软件系统拥抱变化的核心原则之一。对扩展可放,对修改关闭给出了高层次的概括,即在需要对软件进行升级、变化时应该通过扩展的形式来实现,而非修改原有代码。当然这只是一种比较理想的状态,是通过扩展还是通过修改旧代码需要根据代码自身来定。

在Volley中,开闭原则体现得比较好的是Request类族的设计。我们知道,在开发C/S应用时,服务器返回的数据格式多种多样,有字符串类型、xml、json等。而解析服务器返回的Response的原始数据类型则是通过Request类来实现的,这样就使得Request类对于服务器返回的数据格式有良好的扩展性,即Request的可变性太大。

例如我们返回的数据格式是Json,那么我们使用JsonObjectRequest请求来获取数据,它会将结果转成JsonObject对象,我们看看JsonObjectRequest的核心实现。

/**
 * A request for retrieving a {@link JSONObject} response body at a given URL, allowing for an
 * optional {@link JSONObject} to be passed in as part of the request body.
 */
public class JsonObjectRequest extends JsonRequest<JSONObject> {

   // 代码省略
    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString =
                new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(new JSONObject(jsonString),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

JsonObjectRequest通过实现Request抽象类的parseNetworkResponse解析服务器返回的结果,这里将结果转换为JSONObject,并且封装到Response类中。

例如Volley添加对图片请求的支持,即ImageLoader( 已内置 )。这个时候我的请求返回的数据是Bitmap图片。因此我需要在该类型的Request得到的结果是Request,但支持一种数据格式不能通过修改源码的形式,这样可能会为旧代码引入错误。但是你又需要支持新的数据格式,此时我们的开闭原则就很重要了,对扩展开放,对修改关闭。我们看看Volley是如何做的。


/**
 * A canned request for getting an image at a given URL and calling
 * back with a decoded Bitmap.
 */
public class ImageRequest extends Request<Bitmap> {
    // 代码省略

    // 将结果解析成Bitmap,并且封装套Response对象中
    @Override
    protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
        // Serialize all decode on a global lock to reduce concurrent heap usage.
        synchronized (sDecodeLock) {
            try {
                return doParse(response);
            } catch (OutOfMemoryError e) {
                VolleyLog.e("Caught OOM for %d byte image, url=%s", response.data.length, getUrl());
                return Response.error(new ParseError(e));
            }
        }
    }

    /**
     * The real guts of parseNetworkResponse. Broken out for readability.
     */
    private Response<Bitmap> doParse(NetworkResponse response) {
        byte[] data = response.data;
        BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
        Bitmap bitmap = null;
        // 解析Bitmap的相关代码,在此省略

        if (bitmap == null) {
            return Response.error(new ParseError(response));
        } else {
            return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

需要添加某种数据格式的Request时,只需要继承自Request类,并且实现相应的方法即可。这样通过扩展的形式来应对软件的变化或者说用户需求的多样性,即避免了破坏原有系统,又保证了软件系统的可扩展性。

优点

  • 增加稳定性;
  • 可扩展性高。

接口隔离原则 (Interface Segregation Principle)

简述

客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。根据接口隔离原则,当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。

可能描述起来不是很好理解,我们还是以示例来加强理解吧。

示例

我们知道,在Volley的网络队列中是会对请求进行排序的。Volley内部使用PriorityBlockingQueue来维护网络请求队列,PriorityBlockingQueue需要调用Request类的compareTo函数来进行排序。试想一下,PriorityBlockingQueue其实只需要调用Request类的排序方法就可以了,其他的接口它根本不需要,即PriorityBlockingQueue只需要compareTo这个接口,而这个compareTo方法就是我们上述所说的最小接口。当然compareTo这个方法并不是Volley本身定义的接口方法,而是Java中的Comparable接口,但我们这里只是为了学习本身,至于哪里定义的无关紧要。

public abstract class Request<T> implements Comparable<Request<T>> {

    /**
     * 排序方法,PriorityBlockingQueue只需要调用元素的compareTo即可进行排序
     */
    @Override
    public int compareTo(Request<T> other) {
        Priority left = this.getPriority();
        Priority right = other.getPriority();

        return left == right ?
                this.mSequence - other.mSequence :
                right.ordinal() - left.ordinal();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

PriorityBlockingQueue类相关代码 :


public class PriorityBlockingQueue<E> extends AbstractQueue<E>
    implements BlockingQueue<E>, java.io.Serializable {

    // 代码省略

        // 添加元素的时候进行排序
        public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        int n, cap;
        Object[] array;
        while ((n = size) >= (cap = (array = queue).length))
            tryGrow(array, cap);
        try {
            Comparator<? super E> cmp = comparator;
            // 没有设置Comparator则使用元素本身的compareTo方法进行排序
            if (cmp == null)
                siftUpComparable(n, e, array);
            else
                siftUpUsingComparator(n, e, array, cmp);
            size = n + 1;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
        return true;
    }

    private static <T> void siftUpComparable(int k, T x, Object[] array) {
        Comparable<? super T> key = (Comparable<? super T>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = array[parent];
            // 调用元素的compareTo方法进行排序
            if (key.compareTo((T) e) >= 0)
                break;
            array[k] = e;
            k = parent;
        }
        array[k] = key;
    }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

从PriorityBlockingQueue的代码可知,在元素排序时,PriorityBlockingQueue只需要知道元素是个Comparable对象即可,不需要知道这个对象是不是Request类以及这个类的其他接口。它只需要排序,因此我只要知道它是实现了Comparable接口的对象即可,Comparable就是它的最小接口,也是通过Comparable隔离了PriorityBlockingQueue类对Request类的其他方法的可见性。妙哉,妙哉!

优点

  • 降低耦合性;
  • 提升代码的可读性;
  • 隐藏实现细节。

迪米特原则 ( Law of Demeter )

简述

迪米特法则也称为最少知识原则(Least Knowledge Principle),虽然名字不同,但描述的是同一个原则:一个对象应该对其他对象有最少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,这有点类似接口隔离原则中的最小接口的概念。类的内部如何实现、如何复杂都与调用者或者依赖者没关系,调用者或者依赖者只需要知道他需要的方法即可,其他的我一概不关心。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。

迪米特法则还有一个英文解释是: Only talk to your immedate friends( 只与直接的朋友通信。)什么叫做直接的朋友呢?每个对象都必然会与其他对象有耦合关系,两个对象之间的耦合就成为朋友关系,这种关系的类型有很多,例如组合、聚合、依赖等。

示例

例如,Volley中的Response缓存接口的设计。

/**
 * An interface for a cache keyed by a String with a byte array as data.
 */
public interface Cache {
    /**
     * 获取缓存
     */
    public Entry get(String key);

    /**
     * 添加一个缓存元素
     */
    public void put(String key, Entry entry);

    /**
     * 初始化缓存
     */
    public void initialize();

    /**
     * 标识某个缓存过期
     */
    public void invalidate(String key, boolean fullExpire);

    /**
     * 移除缓存
     */
    public void remove(String key);

    /**
     * 清空缓存
     */
    public void clear();

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

Cache接口定义了缓存类需要实现的最小接口,依赖缓存类的对象只需要知道这些接口即可。例如缓存的具体实现类DiskBasedCache,该缓存类将Response序列化到本地,这就需要操作File以及相关的类。代码如下 :


public class DiskBasedCache implements Cache {

    /** Map of the Key, CacheHeader pairs */
    private final Map<String, CacheHeader> mEntries =
            new LinkedHashMap<String, CacheHeader>(16, .75f, true);

    /** The root directory to use for the cache. */
    private final File mRootDirectory;

    public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {
        mRootDirectory = rootDirectory;
        mMaxCacheSizeInBytes = maxCacheSizeInBytes;
    }

    public DiskBasedCache(File rootDirectory) {
        this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);
    }

    // 代码省略
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在这里,Volley的直接朋友就是DiskBasedCache,间接朋友就是mRootDirectory、mEntries等。Volley只需要直接和Cache类交互即可,并不需要知道File、mEntries等对象的存在。这就是迪米特原则,尽量少的知道对象的信息,只与直接的朋友交互。

优点

  • 降低复杂度;
  • 降低耦合度;
  • 增加稳定性。

杂谈

面向对象六大原则在开发过程中极为重要,上述的例子中可能有的不是很合适的示例,我们这里只是抛砖引玉,更深刻的理解需要大家自行学习。如果能够很好地将这些原则运用到项目中,再在一些合适的场景运用一些前人验证过的模式,那么开发出来的软件在一定程度上能够得到质量保证。其实稍微一想,这几大原则最终就化为这么几个关键词: 抽象、单一职责、最小化。那么在实际开发过程中如何权衡、实践这些原则,笔者也在不断地学习、摸索。我想学习任何的事物莫过于实践、经验与领悟,在这个过程中希望能够与大家分享知识、共同进步。

时间: 2024-10-14 02:12:34

[转载] 面向对象编程的6大原则的相关文章

面向对象编程的软件设计原则

在開始Android软件实际APP開始之前,我们须要对面向对象设计原则及设计模式做一个初步的了解.才干在以后的实战过程中,少走弯路.使我们的软件开发生涯感觉到快乐.轻松.好了,废话少说,咱们今天给大家一起探讨一下软OOP中的软件开发设计原则.这些东东都是OOP的设计精髓,他们蕴藏着前辈留下的产物.眼下.软件设计最基本原则有下面几种(总共同拥有11种):单一职责原则.开放封闭原则.依赖倒置原则.接口隔离原则和里氏替换(Liskov替换)原则 单一职责原则 就是一个类值做一件事情.引起它发生变化的仅

为什么使用面向对象编程

因为面向对象编程基于7大原则编写,  这让用面向对象编程编写的程序有了可扩展,可维护,可复用的效果,更灵活一些. 7大原则: (网上看的,解释是自己的理解,不一定对,标准的请上网上) 1.单一职责原则SRP(Single Responsibility Principle)             一个类只负责它本身的功能    这样可以降低类的复杂度,每个类都有了专属的作用,阅读,修改,排错时都更容易             2.开放封闭原则OCP(Open-Close Principle)  

由几道JS笔试题引发的知识点探究十五——JS面向对象编程

JS初学者大都没有认识到其强大的面向对象编程的特性,只是把JS当作一门简单实用的脚本语言来用.也正因如此,JS程序员往往处于程序员鄙视链的最低端,很多人觉得JS是HTML一类的语言,甚至连语言都称不上.事实完全不是如此,你若也有这种想法,说明你对JS的认识太浅薄了.要想正真迈入JS的大门,你必须深入了解JS面向对象编程的特性.下面就让我为大家一一道来. 一.创建对象 既然是面向对象,那肯定先得有对象吧,要有对象,肯定得知道对象是什么吧,那JS中的对象是什么呢?在C++里我们知道,对象就是类或结构

面向对象编程6大设计原则:单一职责原则

单一职责原则(Single  Responsibility Principle)简称SRP原则. 定义 应该有且仅有一个原因引起类的变更. 优点 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多: 提高类的可读性,提高系统的可维护性: 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响. 说明 单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则: 单一职责原则要根据项目的实际情

面向对象编程的三特性、七原则和六视点

一.面向对象的特性 三个基本的特性:封装.继承与多态. 1.封装面向对象编程核心思想这一就是就是将数据和对数据的操作封装在一起.通过抽象,即从具体的实例中抽取共同的性质形成一般的概念,比如类的概念. 2.继承继承体现了一种先进的编程模式.子类可以继承父类的属性和功能,即子类继承了父类所具有的数据和数据上的操作,同时又可以增添子类独有的数据和数据上的操作.例如,"人类"继承了"哺乳类"的属性和功能,同时又增添了人类独有的属性和功能. 3.多态 多态是面向对象编程的又一

面向对象的十大原则

面向对象设计原则是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心,但大多数Java程序员追逐像Singleton.Decorator.Observer这样的设计模式,而不重视面向对象的分析和设计.甚至还有经验丰富的Java程序员没有听说过OOPS和SOLID设计原则,他们根本不知道设计原则的好处,也不知道如何依照这些原则来进行编程. 众所周知,Java编程最基本的原则就是要追求高内聚和低耦合的解决方案和代码模块设计.查看Apac

我是怎样教媳妇面向对象编程的 (转载)

简介 我老婆 Farhana 想要继续软件开发生涯(之前因为我们的第一个孩子出生,她不得不放弃).我已经有了一些软件设计和开发的经验,所以这几天我就在试着帮助她学习OOD. 由于我早年在软件开发的经验,我总是发现无论一个技术问题看上去多么难搞,只要从现实生活的角度去解释或用对话的方式去讨论总能让它变得更简单.关于OOD,我们已经有了许多成果丰硕的讨论,我觉得有人可能发现这是一个学习OOD有趣的方式,所以我想我应该分享出来. 下面是我们的谈话步骤: 话题:介绍面向对象设计 丈夫:亲爱的,让我们开始

面向对象编程的六大原则

一.单一职责原则: 全称:“Single-Responsibility Principle” 说明:就一个类而言,应该只专注于做一件事和仅有一个引起它变化的原因.所谓职责,我们可以理解他为功能,就是设计的这个类功能应该只有一个,而不是两个或更多.也可以理解为引用变化的原因,当你发现有两个变化会要求我们修改这个类,那么你就要考虑撤分这个类了.因为职责是变化的一个轴线,当需求变化时,该变化会反映类的职责的变化. 使用SRP注意点: 1.一个合理的类,应该仅有一个引起它变化的原因,即单一职责: 2.在

面向对象编程思想的哲学起源(转载)

http://www.xuebuyuan.com/566309.html 本来想象着写一整篇「面向对象编程思想的哲学起源」这样的题目,笔走纸上,方才发现这样的题目足够出本书,知识不够,写不动.但心里还是想写点自己的所思所想. 全篇就拿JAVA来举例了.众所周知,面向对象的四大基本要素:抽象(Abstract).封装(Encapsulation).继承(Inheritance).多态(Polymorphism). 很多人坚持<逻辑学>是唯物哲学的基础,不懂,姑且不论.哲学就是对自然学科的抽象,看