CSDN blog recommended article Http://prog3.com/sbdm/blog Http://prog3.com/sbdm/static.blog/images/logo.gif CSDN blog content aggregation service Http://prog3.com/sbdm/blog Zh-cn (C) 2011 PROG3.COM Http://prog3.com/sbdm/blog 0:12:59 2015/11/30 Object oriented six principles Http://prog3.com/sbdm/blog/bboyfeiyu/article/details/50103471 Http://prog3.com/sbdm/blog/bboyfeiyu/article/details/50103471 Bboyfeiyu 0:10:44 2015/11/30

1, the first step of optimizing the code - a single responsibility principle

The Responsibility Principle Single, or SRP. Its definition is: in a class, there should be only one reason to change it. In simple terms, a class should be a set of high correlation function, data encapsulation. As Qin Xiaobo in the "design pattern of Zen," said: "this is a highly controversial but also its important principle. If you want to argue with others, angry or quarrel, this principle have proved effective every time ". Because the division of a single function is not always so clear, many times is the need to rely on personal experience to define. Of course, the biggest problem is the definition of a job, what is the responsibility of the class, and how to divide the responsibilities of the class.
In the case of computer technology, usually only simply learning theoretical knowledge and cannot very good understanding of the meaning, only their own hands-on practice and in practice found the problem, problem solving, thinking, can the knowledge absorbed into his mind. Below to my friends, the story of the small people.

Since the Android system has been released, the small people is a big fan of Android, so during the university has maintained a focus on Android, and the use of spare time to do some small projects, exercise their own ability to combat. After graduation, the small people get to join the right company, and put into his love of Android application development industry. Love, life, career com., the first job is smooth, all in grasping.
After a week of adaptation and familiar with the company's products, the development of standards, the development of the small people to start the work. Small people's supervisor is a seasoned technical experts, for small people work is not very satisfactory, especially young people the weakest of object-oriented design, and Android development is using the Java language. Nouns in some abstract, interface, six principles, 23 kinds of design patterns to small people were confused and disoriented. Small people themselves are aware of their own problems, so, the executive director of the small people decided to let the people do a small project to exercise the capacity of this area. Is the day of reckoning, modaobuwukanchaigong, the development of the road has just begun.

After a lot of thinking, the competent selection of the use of a wide range of difficulty is also moderate ImageLoader (picture loading) as a training program for small people. Since the object oriented design of the small people, then we must take into account the scalability, flexibility, and detect whether the best way to meet the needs of the best way is open source. Users continue to put forward demand, feedback problems, the project needs of the small people constantly upgrade to meet the needs of users, and to ensure the stability and flexibility of the system. After the executive with the small people said that this special task, the small people first felt the pressure, life is not easy!" Only 22 years of age so far, unmarried people issued such a profound sigh!

Challenges are always face, not to mention the small people who have never been. The supervisor's request is very simple, want the small people to realize the picture to load, and want to cache the picture. After the analysis of the demand, the small people on the rest assured that, so simple, I thought it was very difficult......" To oneself Wang has enough chest. After ten minutes of encoding, the small people wrote the following code:

/ * *
* image loading class
* /
Public Class ImageLoader{
    / / image cache
Bitmap>, mImageCache LruCache<String;
    / / thread pool, thread number number is CPU
MExecutorService ExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime ().AvailableProcessors ());

    Public ImageLoader(1)
InitImageCache ();
}

    Private Void InitImageCache(1)
            The maximum memory can be used to calculate / /
        Final IntMaxMemory = (Int(Runtime.getRuntime ().MaxMemory () /1024);
            / /取四分之一的可用内存作为缓存
        最终的 intcachesize = maxmemory /4;
mimagecache =新的lrucache <字符串>,位图(cachesize){

            “覆盖
            保护区 int sizeof(String key,位图){
                Returnbitmap.getrowbytes()()/ bitmap.getheight *1024;
}
};
}

    公共的  无效 displayimage最终的字符串的URL,最终的imageview imageview){
imageview.settag(URL);
mexecutorservice.submit(新的runnable(){

           “覆盖
            公共的  无效 运行(){
downloadimage位图=(URL);
                如果(位图= =){
                    Return;
}
                如果(imageview.gettag().equals(URL)){
imageview.setimagebitmap(位图);
}
mimagecache.put(URL,位图);
}
});
}

    公共的位图downloadimage(String imageurl){
位图=尝试{
newurl url =(imageurl);
            最终的httpurlconnection conn =
(httpurlconnection)url.openconnection();
(= bitmapfactory.decodestream位图
conn.getinputstream());
conn.disconnect();
}摔跤(例外(e){
e.printstacktrace();
}

        Return位图;
}
}

并且使用git软件进行版本控制,将工程托管到github上,伴随着git push命令的完成,小民的imageloader 0.1版本就正式发布了!如此短的时间内就完成了这个任务,而且还是一个开源项目,小民暗暗自喜,幻想着待会儿主管的称赞。

在小民给主管报告了imageloader的发布消息的几分钟之后,主管就把小民叫到了会议室.这下小民纳闷了,怎么夸人还需要到会议室.”小民,你的imageloader耦合太严重啦!简直就没有设计可言,更不要说扩展性、灵活性了.所有的功能都写在一个类里怎么行呢,这样随着功能的增多,imageloader类会越来越大,代码也越来越复杂,图片加载系统就越来越脆弱……”的形成,这简直就是当头棒喝,小民的脑海里已经听不清主管下面说的内容了,只是觉得自己之前没有考虑清楚就匆匆忙忙完成任务,而且把任务想得太简单了。

“你还是把imageloader拆分一下,把各个功能独立出来,让它们满足单一职责原则。”主管最后说道.小民是个聪明人,敏锐地捕捉到了单一职责原则这个关键词.用google搜索了一些优秀资料之后总算是对单一职责原则有了一些认识.于是打算对imageloader进行一次重构.这次小民不敢过于草率,也是先画了一幅uml图,如图1 - 1所示.

图1 - 1

imageloader代码修改如下所示:

* / *
*图片加载类
* /
公共的   imageloader{
    / /图片缓存
imagecache mimagecache =新的imagecache();
    / /线程池,线程数量为cpu的数量
executorservice mexecutorservice = executors.newfixedthreadpool(runtime.getruntime .availableprocessors()());

    / /加载图片
    公共的  无效 displayimage最终的字符串的URL,最终的imageview imageview){
mimagecache.get位图=(URL);
        如果(位图。=){
imageview.setimagebitmap(位图);
            Return;
}
imageview.settag(URL);
mexecutorservice.submit(新的runnable(){

            “覆盖
            公共的 无效 运行(){
downloadimage位图=(URL);
                如果(位图= =){
                    Return;
}
                如果(imageview.gettag().equals(URL)){
imageview.setimagebitmap(位图);
}
mimagecache.put(URL,位图);
}
});
}

    公共的位图downloadimage(String imageurl){
位图=尝试{
url =新的URL(imageurl);
            最终的httpurlconnection conn =
(httpurlconnection)
url.openconnection();
bitmapfactory.decodestream位图=(conn.getinputstream());
conn.disconnect();
}摔跤(例外(e){
e.printstacktrace();
}
        Return位图;
}
}

并且添加了一个imagecache类用于处理图片缓存,具体代码如下:

公共 等级 ImageCache{
    / /图片LRU缓存
<字符串> mimagecache LruCache,位图;

    公共 ImageCache(){
initimagecache();
}

    私人 无效 initimagecache(){
         / /计算可使用的最大内存
        最后 国际的maxmemory =(国际的(运行时)。getruntime() maxmemory() /。1024);
        / /取四分之一的可用内存作为缓存
        最后 国际的CacheSize = maxmemory /4;
mimagecache =新的LruCache <字符串>,位图(CacheSize){

            “重写”
            受保护的 国际的 sizeof(字符串键、位图位图){
                返回getrowbytes() *位图。
getheight() /位图。1024;
}
};
}

    公共 无效 (字符串网址,位图位图){
mimagecache放(URL,位图);
}

    公共位图得到(字符串网址){
        返回mimagecache得到(URL);
}
}

如图1-1和上述代码所示,小民将imageloader一拆为二,imageloader只负责图片加载的逻辑,而ImageCache只负责处理图片缓存的逻辑,这样imageloader的代码量变少了,职责也清晰了,当与缓存相关的逻辑需要改变时,不需要修改imageloader类,而图片加载的逻辑需要修改时也不会影响到缓存处理逻辑。主管在审核了小民的第一次重构之后,对小民的工作给予了表扬,大致意思是结构变得清晰了许多,但是可扩展性还是比较欠缺,虽然没有得到主管的完全肯定,但也是颇有进步,再考虑到自己确实有所收获,小民原本沮丧的心里也略微地好转起来。

从上述的例子中我们能够体会到,单一职责所表达出的用意就是”单一”二字。正如上文所说,如何划分一个类、一个函数的职责,每个人都有自己的看法,这需要根据个人经验、具体的业务逻辑而定。但是,它也有一些基本的指导原则,例如,两个完全不一样的功能就不应该放在一个类中。一个类中应该是一组相关性很高的函数、数据的封装。工程师可以不断地审视自己的代码,根据具体的业务、功能对类进行相应的拆分,我想这会是你优化代码迈出的第一步。

2、让程序更稳定、更灵活——开闭原则

开闭原则的英文全称是开闭原则,简称OCP,它是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的、灵活的系统。开闭原则的定义是:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是,对于修改是封闭的。在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会将错误引入原本已经经过测试的旧代码中,破坏原有系统。因此,当软件需要变化时,我们应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现。当然,在现实开发中,只通过继承的方式来升级、维护原有系统只是一个理想化的愿景,因此,在实际的开发过程中,修改原有代码、扩展代码往往是同时存在的。

软件开发过程中,最不会变化的就是变化本身。产品需要不断地升级、维护,没有一个产品从第一版本开发完就再没有变化了,除非在下个版本诞生之前它已经被终止。而产品需要升级,修改原来的代码就可能会引发其他的问题。那么如何确保原有软件模块的正确性,以及尽量少地影响原有模块,答案就是尽量遵守本章要讲述的开闭原则。

勃兰特·梅耶在1988年出版的《面向对象软件构造》一书中提出这一原则。这一想法认为,一旦完成,一个类的实现只应该因错误而被修改,新的或者改变的特性应该通过新建不同的类实现。新建的类可以通过继承的方式来重用原类的代码。显然,梅耶的定义提倡实现继承,已存在的实现对于修改是封闭的,但是新的实现类可以通过覆写父类的接口应对变化。
Said so much, everybody is not completely understand, let us take a simple example to explain.

After a reconstruction of the ImageLoader, the small people of this open source library to get some users. For the first time, the small people feel that they invented the wheel of pleasure, the enthusiasm of the open source is also more and more high! Through the implementation of some open source library to in-depth learning related technologies, not only to improve themselves, but also to better use these technologies to work, so as to develop a more stable and excellent application, which is the real idea of small people.

After the first round of the small people's first round of restructuring ImageLoader responsibilities of a single, clear structure, not only to get a point in charge of the charge, but also get the user's praise, is a good start. With the increase in the number of users, some of the problems also exposed, the small people's cache system is the most of the place where tucao. Memory buffer to solve the problem from the network load each time, but the memory of Android application is very limited, and it is easy to lose, that is, when the application is restarted, the original has been loaded after the picture will be lost, so restart after the need to re download! This will lead to the problem of loading slow and consuming user traffic. Small people consider the introduction of the SD card cache, so that the downloaded picture will be cached to the local, even if the application does not need to restart the application! After discussing the problem with the supervisor, the young people put into programming. The following is the code of the young people.
DiskCache.java class, the picture is cached to the SD card:

Public Class DiskCache{
    For the sake of simplicity / write a temporary path, in the development of this kind of writing, please avoid!
    StaticCacheDir String ="Sdcard/cache/";
     / / get a picture from the cache
    PublicBitmapGet(URL String) {
        ReturnBitmapFactory.decodeFile (cacheDir + URL);
}

    The picture / cache memory
    Public  Void  Put(URL Bitmap, BMP String) {
FileOutputStream FileOutputStream =Null;
        Try{
FileOutputStream =New 
FileOutputStream (cacheDir + URL);
Bmp.compress (CompressFormat.PNG,
                 One hundredFileOutputStream);
}Catch(E FileNotFoundException) {
E.printStackTrace ();
}Final{ly
            If(fileOutputStream! =Null{)
                Try{
FileOutputStream.close ();
}Catch(E IOException) {
E.printStackTrace ();
}
}
}
}
}

Because you need to cache the image to the SD card, so, the ImageLoader code has been updated, the specific code is as follows:

Public Class ImageLoader{
    / / memory cache
MImageCache ImageCache =NewImageCache ();
    The cache / SD card
MDiskCache DiskCache =NewDiskCache ();
    Whether to use the SD card / cache
    BooleanIsUseDiskCache =False;
    / / thread pool, thread number number is CPU
MExecutorService ExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime ().AvailableProcessors ());


    Public  Void DisplayImage(FinalURL String,FinalImageView ImageView) {
        What kind of judgment / cache
Bitmap Bitmap = isUseDiskCache? MDiskCache.get (URL)
MImageCache.get (URL);
        If(bitmap! =Null{)
ImageView.setImageBitmap (bitmap);
            Return;
}
        / / no caching, are referred to the thread pool to download
}

    Public Void UseDiskCache(BooleanUseDiskCache) {
IsUseDiskCache = useDiskCache;
}
}

From the above code can be seen, just add a DiskCache class and ImageLoader class to join a small amount of code added to the function of the SD card cache, the user can use the useDiskCache method to set up the use of what kind of cache, for example:

ImageLoader ImageLoader =NewImageLoader ();
 Using the SD card / cache
ImageLoader.useDiskCache (True);
/ / use of memory cache
ImageLoader.useDiskCache (False);

UseDiskCache method can let users set up different cache, very convenient ah! Small people are very satisfied with this, then submitted to the competent to do code review. "Small people, you thought is right, but some obvious problems, is the use of memory cache when the user can not use the SD card cache, similar to the use of SD card when the user can not use the memory cache memory. The user needs these two strategies, first of all, the first cache memory cache memory, if the memory is no picture then use the SD card cache, if there is no picture in the SD card to get from the network, which is the best caching strategy." It is in charge of people then pierce to the heart of the matter, just as if wakening from a dream face, also feel oneself highly flattered suddenly some red......
So the young people in accordance with the guidance of a new double cache DoudleCache, specific code is as follows:

/ * *
* double buffer. When you get the picture, you can get it from the memory cache. If you don't have to cache the image in memory, then get it from the SD card.
* cache memory is also in memory and the SD card to cache a copy
* /
Public Class DoubleCache{
MMemoryCache ImageCache =NewImageCache ();
MDiskCache DiskCache =NewDiskCache ();

    / / the first get a picture from the memory cache, if not, to get from the SD card
    PublicBitmapGet(URL String) {
Bitmap Bitmap = mMemoryCache.get (URL);
        If(bitmap = =Null{)
Bitmap = mDiskCache.get (URL);
}
        ReturnBitmap;
}

    The picture / cache memory and SD card
    Public Void Put(URL Bitmap, BMP String) {
MMemoryCache.put (URL, BMP);
MDiskCache.put (URL, BMP);
}
}

Let's look at the latest ImageLoader class, the code update is not much:

Public Class ImageLoader{
    / / memory cache
MImageCache ImageCache =NewImageCache ();
    The cache / SD card
MDiskCache DiskCache =NewDiskCache ();
    / / double buffer
MDoubleCache DoubleCache =NewDoubleCache ();
    Using the SD card / cache
    BooleanIsUseDiskCache =False;
    / / the use of double buffering
    BooleanIsUseDoubleCache =False;
    / / thread pool, thread number number is CPU
MExecutorService ExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime ().AvailableProcessors ());


    Public Void DisplayImage(FinalURL String,FinalImageView ImageView) {
BMP Bitmap =Null;
         If(isUseDoubleCache) {
BMP = mDoubleCache.get (URL);
}Else If(isUseDiskCache) {
BMP = mDiskCache.get (URL);
}Else{
BMP = mImageCache.get (URL);
}

         If(BMP! =Null{)
ImageView.setImageBitmap (BMP);
}
        / / no caching, are referred to the thread pool for asynchronous download pictures
}

    Public Void UseDiskCache(BooleanUseDiskCache) {
IsUseDiskCache = useDiskCache;
}

    Public Void UseDoubleCache(BooleanUseDoubleCache) {
IsUseDoubleCache = useDoubleCache;
}
}

By adding just a few code and a few changes to the completion of such an important function. People have been increasingly feel that their own Android development has reached a handy position, not only feel the spring breeze blow, his flowing hair about from his eyes brushed, small people feeling in the sky today than many of the usual bright.

"Small people, you each time you add a new cache method to modify the original code, it is likely to introduce Bug, and will make the original code logic becomes more and more complex, in accordance with your method to achieve, the user can not customize the cache!" In the end is the high level of the language, a word out of the small people this cache design issues.

We analyze the procedure of the small people, the small people in the program to add a new cache implementation need to modify the ImageLoader class, and then through a boolean variable to let the user to use which kind of cache, so there are a variety of ImageLoader in the if-else judgment, through these judgments to determine which kind of cache. With the introduction of these logics, the code becomes more and more complex and fragile, if small people accidentally wrong a if condition (condition too much, it is very prone to), it would need to more time to exclude. The whole ImageLoader class will become increasingly bloated. The most important is that the user can not implement the cache injection to the ImageLoader, but the most important feature of the framework is the extension of the.

"Objects (classes, modules, functions, etc.) in the software should be open, but for the changes to be closed, this is the open - closed principle. That is to say, when the software needs to change, we should try to change through the way of the extension, rather than by modifying the existing code to achieve." The director added, Wang heard foggy. In charge of small people this reaction, so the "surgeon", as he himself drew the Figure 1-2 figure UML.


Figure 1-2

Small people see Figure 1-2 seems to understand what, but it is not very clear how to modify the program. In charge of seeing the young people like to go into battle, with a small people to the ImageLoader program in accordance with the Figure 1-2 a reconstruction. Specific code is as follows:

Public Class ImageLoader{
    / / image cache
MImageCache ImageCache =NewMemoryCache ();
    / / thread pool, thread number number is CPU
MExecutorService ExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime ().AvailableProcessors ());

    Injection / cache
    Public Void SetImageCache(CACHE ImageCache) {
MImageCache = cache;
}

    Public Void DisplayImage(imageUrl ImageView, imageView String) {
Bitmap Bitmap = mImageCache.get (imageUrl);
        If(bitmap! =Null{)
ImageView.setImageBitmap (bitmap);
            Return;
}
        No pictures / / cache, submit to the thread pool to download pictures
SubmitLoadRequest (imageUrl, imageView);
}

    Private Void SubmitLoadRequest(FinalImageUrl String,
             FinalImageView ImageView) {
ImageView.setTag (imageUrl);
MExecutorService.submit (NewRunnable () {

            @Override
            Public  Void Run(1)
Bitmap Bitmap = downloadImage (imageUrl);
                If(bitmap = =Null{)
                    Return;
}
               If(imageView.getTag ().Equals (imageUrl)) {
ImageView.setImageBitmap (bitmap);
}
MImageCache.put (imageUrl, bitmap);
}
});
}

    PublicBitmapDownloadImage(imageUrl String) {
Bitmap Bitmap =Null;
        Try{
URL URL =NewURL (imageUrl);
            FinalConn HttpURLConnection = (HttpURLConnection)
Url.openConnection ();
Bitmap = BitmapFactory.decodeStream (conn.getInputStream ());
Conn.disconnect ();
}Catch(E Exception) {
E.printStackTrace ();
}

        ReturnBitmap;
}
}

After this reconstruction, there is no so many if-else statements, no variety of cache to achieve the object, Boolean variables, the code is clear and simple, a lot of small people on the charge of the situation and the flood of. It should be noted that the ImageCache class here is not the original one of the ImageCache, the program is responsible for the reconstruction of the program to extract the interface into a picture cache, used to abstract image cache function. We look at the declaration of the interface:

Public Interface ImageCache{
    PublicBitmapGet(URL String);
    Public Void Put(URL Bitmap, BMP String);
}

ImageCache interface simple definition of the acquisition, the cache of the two functions of the picture, the key is the URL of the image, the value is the picture itself. The memory buffer, the SD card cache, and the double buffer are implemented:

/ / memory cache MemoryCache
Public Class MemoryCache Implements ImageCache{
    PrivateBitmap>, mMemeryCache LruCache<String;

    Public MemoryCache(1)
        / / initialize the LRU cache
}

     @Override
    PublicBitmapGet(URL String) {
        ReturnMMemeryCache.get (URL);
}

    @Override
    Public Void Put(URL Bitmap, BMP String) {
MMemeryCache.put (URL, BMP);
}
}

The DiskCache class cache / SD card
Public  Class  DiskCache Implements ImageCache{
    @Override
    PublicBitmapGet(URL String) {
        Return NullGet the picture from the local / * * / file;
}

    @Override
    Public Void Put(URL Bitmap, BMP String) {
        Write the Bitmap file in /
}
}

Double buffer / / DoubleCache
Public Class DoubleCache Implements ImageCache{
MMemoryCache ImageCache =NewMemoryCache ();
MDiskCache ImageCache =NewDiskCache ();

    / / the first get a picture from the memory cache, if not, to get from the SD card
    PublicBitmapGet(URL String) {
Bitmap Bitmap = mMemoryCache.get (URL);
        If(bitmap = =Null{)
Bitmap = mDiskCache.get (URL);
}
        ReturnBitmap;
}

    The picture / cache memory and SD card
    Public Void Put(URL Bitmap, BMP String) {
MMemoryCache.put (URL, BMP);
MDiskCache.put (URL, BMP);
}
}

Careful friends may notice that the ImageLoader class adds an setImageCache (CACHE ImageCache) function that can be implemented by the user to set up the cache, which is usually dependent on the injection. Below to see how the user is set to set the cache:

ImageLoader ImageLoader =NewImageLoader ();
        / / use of memory cache
ImageLoader.setImageCache (NewMemoryCache ());
        Using the SD card / cache
ImageLoader.setImageCache (NewDiskCache ());
        / / the use of double buffering
ImageLoader.setImageCache (NewDoubleCache ());
        Use a custom image cache implementation /
ImageLoader.setImageCache (NewImageCache () {

            @Override
        Public Void Put(URL Bitmap, BMP String) {
            Picture / cache
}

            @Override
        PublicBitmapGet(URL String) {
            Return Null/ * * / get a picture from the cache;
}
});

In the above code, the setImageCache (CACHE ImageCache) method is injected into different cache, which can not only make the ImageLoader more simple and robust, but also makes the scalability and flexibility of ImageLoader. MemoryCache, DiskCache, DoubleCache cache picture of the specific implementation is completely different, however, they are a feature of the ImageCache interface has been achieved. When a user needs to implement the caching strategy, a new class of ImageCache interface is required to construct the object, and setImageCache (CACHE ImageCache) is injected into the ImageLoader, so that the ImageLoader can achieve a change of the cache strategy, and the expansion of these caching policies will not lead to the ImageLoader class. After this reconstruction, the small people's ImageLoader has been basically qualified. Hey! This is not the principle of open and close by the supervisor! "Objects (classes, modules, functions, etc.) in the software should be open, but the changes are closed. And the important way to follow the principle of opening and closing is the abstract......" Wang said in a whisper, into thinking......

When the software needs to change, we should try to change the way to achieve the change, and not through the modification of the existing code to achieve. Here "should try" 4 words that OCP principle and not say absolutely can not modify the original class, when we smell the original code "rotten smell", should be reconstruction as early as possible, to make code returned to normal "evolution" track, rather than through inheritance add new implementations, which will lead to type of expansion and of legacy code redundancy. Our development process is not so ideal condition, completely without modifying the original code, therefore, in the development process need to combine their own specific circumstances, is through the modification of the old code or through inheritance makes the software system is more stable and more flexible, in order to ensure the removal of "code corruption", but also to ensure the correctness of the original module.

3, to build a better system of expansion - on the scale of the principle of substitution

The LSP Principle Liskov is the abbreviation of the Substitution. Its first definition is: if the object O1 s for each type have type t object O2, making to define a t all program P in all of the object O1 is substituted for O2, the behavior of a program P does not change, then s type is sub types of type T. The described above is really not very good understanding, theorists sometimes easy to abstract, have been very easy to understand the things make them a generalization is made a mouthful. Let's see another straightforward definition. Second definitions: all references to the base class must be able to use the object in a transparent manner.

We know that the three feature of object-oriented language is inheritance, encapsulation, polymorphism, the principle of the scale of the scale is dependent on Yu Jicheng, the two major characteristics of this. The principle of measuring the scale on the scale is simply that all references to the base class must be transparent to the object of its subclasses. Popular point, as long as the parents can appear in the place where the child can appear, and replaced as a child will not produce any errors or exceptions, users may not need to know is the parent class or subclass. But, in turn, not the kind of place where there are children, the parents may not be able to adapt to the. Said so much, in fact, the final summary of the two words: abstract.
In order to understand the relationship between Window and View in, a simple example was written in order to understand the relationship between 1-3 and Android.

Figure 1-3 3

We look at the code:

/ / the window class
Public Class Window{
    Public Void Show(child View) {
Child.draw ();
}
}

Create view / view abstraction, measurement and breadth of the public code, drawn to concrete subclasses
Public Abstract Class  View{
    Public Abstract Void  Draw();
    Public Void  Measure(IntWidth,IntHeight) {
        / / view size measurement
}
}

/ / implementation button class
Public Class Button Extends View{
    Public Void Draw(1)
        / / draw the button
}
}
The realization of TextView / /
Public Class TextView Extends View{
    Public Void Draw(1)
        / / draw text
}
}

In the example above, Window relies on View, while View defines a view abstraction. Measure is a method for each sub class, and the sub class has its own features, in which the function is to draw its own content. Any sub class that inherits from the View class can be set to the show method, and we have to replace the. By replacing the, you can customize a variety of View, and then passed to the Window, Window is responsible for organizing the View, and the View is displayed on the screen.
The core principle of the substitution principle of the scale on the scale is abstract, and abstract and depend on the characteristics of the inheritance. In the OOP, the advantages and disadvantages are quite obvious.
Advantages are as follows:

  • (1) code reuse, reducing the cost of creating a class, each subclass has a method and property of the parent class;
  • (2) the child is similar to that of the parent class, but it is different from the father;
  • (3) improving the scalability of the code.

Disadvantages of inheritance:

  • (1) the inheritance is intrusive, so long as it is necessary to inherit all the properties and methods of the parent class;
  • (2) it may cause redundancy and flexibility of the subclass code to be redundant, because the subclass must have the attributes and methods of the parent class.

Things always have two sides, how to weigh the pros and cons of the need to make a choice according to the specific scene and to deal with it. On the principle of measuring the scale of the on the scale, we should build up a better software system, and we will continue to do so in the ImageLoader.
Figure 1-2 above also has a good response to the principle of the MemoryCache, that is, DiskCache, DoubleCache, ImageCache can replace the work of the, and can ensure the correctness of the behavior. ImageCache set up the interface specification, MemoryCache, etc. according to the interface specification to achieve the corresponding function, users only need to specify a specific cache object in the use of ImageLoader can be dynamically replace the cache strategy. This makes the ImageLoader caching system has the possibility of wireless, which is to ensure the scalability.

Imagine a scene when the cache object in setImageCache (CACHE ImageCache) is not able to replace the object in the ImageLoader object, then how do users set up different cache objects and how the user can customize their own cache, through the useDiskCache method in Section 1.3? Obviously not, on the scale, the principle of measuring on the scale of this kind of problem to provide the guiding principle, that is, the establishment of the abstract, the establishment of norms, the concrete implementation of the operation to replace the abstract, to ensure the system's high scalability, flexibility. Opening and closing principle and Liskov Substitution Principle is often in life and death, not abandon, the Liskov Substitution to open for extension, to modify the effect of the closure. However, these two principles also emphasize the important characteristic of OOP. Therefore, it is an important step in the process of development.

4, to allow the project to have the ability to change - - dependent on the principle of inversion

Inversion Principle Dependence, or DIP. The dependency inversion principle refers to a specific form of decoupling, which makes the high level module independent of the implementation details of the low level module, and the module is reversed. This concept is a bit of a bad idea, what does that mean?
Several key points of dependency inversion principle:

  • (1) high level modules should not depend on the low level module, both of which rely on their abstract;
  • (2) the abstract should not rely on details;
  • (3) details should depend upon abstractions.

In Java language, the abstract is the interface or abstract class, the two are not directly be able to be directly; the details are to achieve the class, the interface or the inheritance of the class is the details, which is characterized by that it can be directly, that is, to add a keyword new generated an object. High level module is called the end, the low level module is the concrete realization. The performance of the dependency inversion principle in Java language is that the dependency between the modules is achieved by the abstraction, and the dependence relation is not directly dependent on the class. This is another example of the theoretical abstraction, in fact, a word can be summarized: the interface oriented programming, or the abstract programming, where the abstract refers to the interface or abstract class. Interface oriented programming is one of the object's essence, which is the abstract of the above two stresses.

If the class and class are directly dependent on the details, then there is a direct coupling between them, when the specific implementation needs to be changed, which means that in the same time to modify the code, and limits the scalability of the system. We look at the 1.3 section of the graph 1-3, ImageLoader is directly dependent on MemoryCache, the MemoryCache is a concrete implementation, rather than an abstract class or interface. This has led to the ImageLoader directly dependent on the specific details, when MemoryCache can not meet the ImageLoader and the need to be replaced by other cache, this time you must modify the ImageLoader code, for example:

Public Class ImageLoader{
    / / memory cache (directly dependent on the details)
MMemoryCache MemoryCache =NewMemoryCache ();
     Load the image into ImageView / /
    Public Void DisplayImage(URL ImageView, imageView String) {
BMP Bitmap = mMemoryCache.get (URL);
        If(BMP = =Null{)
DownloadImage (URL, imageView);
}Else{
ImageView.setImageBitmap (BMP);
}
}

    Public Void SetImageCache(CACHE MemoryCache) {
MCache = cache;
}
    / / code omitted
}

With the upgrade of products, users find that MemoryCache has no longer meet the needs of the user needs of the small people's ImageLoader can be cached to the memory and the SD card, or allows users to customize the realization of the cache. At this time, we MemoryCache the class name not only not to express the meaning of the cache of memory and SD card, also can not meet the function. In addition, users need to customize the cache must be inherited from the MemoryCache, and the user's cache memory is not necessarily related to memory cache, which in the name of the restrictions also make the user experience is not good. The first scheme of the small people is to modify the MemoryCache to DoubleCache, and then implement the specific caching function in DoubleCache. We need to modify the ImageLoader as follows:

Public Class ImageLoader{
    / / double buffer (directly dependent on the details)
MCache DoubleCache =NewDoubleCache ();
    Load the image into ImageView / /
    Public Void DisplayImage(URL ImageView, imageView String) {
BMP Bitmap = mCache.get (URL);
        If(BMP = =Null{)
          / / asynchronous download pictures
DownloadImageAsync (URL, imageView);
}Else{
ImageView.setImageBitmap (BMP);
}
}

    Public Void SetImageCache(CACHE DoubleCache) {
MCache = cache;
}
    / / code omitted
}

We will revise MemoryCache DoubleCache, then amended the ImageLoader class cache of the concrete realization easily satisfy the needs of users. Wait This does not depend on the concrete implementation class (DoubleCache)? When the user needs to change again, we have to modify the cache to achieve class and ImageLoader code to achieve? Does not violate the original code in violation of the 1.3 section of the open and close principle? Small people suddenly wake up, low head thinking how to make the system more flexible, embrace change......

Of course, these are in charge of the 1-2 (Section 1.3) and the corresponding code before the suffering of the small people experience. Since this is the way it is clear that the solution given by the supervisor will be able to make the caching system more flexible. In a word, it is to rely on abstractions without relying on concrete implementation. For the image cache, the supervisor builds the ImageCache abstraction, which adds the get and put methods to achieve the image's access. Each buffer implementation must implement this interface, and implement its access method. When users need to use a different cache to achieve, directly through the dependency injection can ensure the flexibility of the system. Let's look at the code:

ImageCache cache abstraction:

Public Interface ImageCache{
    PublicBitmapGet(URL String);
    Public Void Put(URL Bitmap, BMP String);
}

ImageLoader class:

Public Class ImageLoader{
    / / class depends on the image cache, abstraction, and a default implementation
MCache ImageCache =NewMemoryCache ();

    / / loading picture
    Public Void DisplayImage(URL ImageView, imageView String) {
BMP Bitmap = mCache.get (URL);
        If(BMP = =Null{)
        / / asynchronousloading picture
DownloadImageAsync (URL, imageView);
}Else{
ImageView.setImageBitmap (BMP);
}
}

    / * *
* set cache policy, depending on the abstract
* /
    Public Void SetImageCache(CACHE ImageCache) {
MCache = cache;
}
    / / code omitted
}

Here, we set up the ImageCache abstraction, and let ImageLoader depend on the abstract rather than the concrete details. When the need to change, the small people only need to implement the ImageCahce class or inheritance of other existing ImageCache subclass to complete the corresponding cache function, and then the specific implementation of the ImageLoader to achieve the replacement of the cache function, which ensures that the cache system of the Gao Kekuo show, has the ability to embrace change, and all the basic guiding principle is our dependence on the inverted principle. From the above sections we find that we want to make our system more flexible and abstract it seems to be the only way we are.

5, the system has a higher flexibility - the principle of interface segregation

The principle of Principles InterfaceSegregation is ISP. Its definition is: the client should not depend on the interface it does not need. The other definition is: the dependency relationship between classes should be based on the minimal interface. Interface isolation principle will be very large, bloated interface split into smaller and more specific interface, so that customers will only need to know the way they are interested. The purpose of the interface isolation principle is to unlock the system, thus it is easy to reconstruct, change and re deploy.

Interface Segregation Principle to put it plainly is, let the client dependent interface as small as possible, this may still be a bit abstract, we still with an example to explain. Before we have a scene, in Java 6 and before the JDK version, there is a very annoying problem, that is, after using the OutputStream or other can be closed down, we have to ensure that they are finally closed, we have such a code in the SD card:

The picture / cache memory
Public Void Put(URL Bitmap, BMP String) {
FileOutputStream FileOutputStream =Null;
    Try{
FileOutputStream =NewFileOutputStream (cacheDir + URL);
Bmp.compress (CompressFormat.PNG,One hundredFileOutputStream);
}Catch(E FileNotFoundException) {
E.printStackTrace ();
}Finally{
        If(fileOutputStream! =Null{)
            Try{
FileOutputStream.close ();
}Catch(E IOException) {
E.printStackTrace ();
}
}End / / if
}If finally / / end
}

We see this code readability is very poor, all kinds of try... Catch nesting, are some simple code, but it will seriously affect the readability of the code, and the multi - level of large brackets are easy to write code to the wrong level. We should also be very disgusted with this kind of code, then we see how to solve these problems.
We may know that there is a Closeable interface in Java, which identifies an object that can be closed. It has only one close method, as shown in Figure 1-4.
We want to talk about the FileOutputStream class to achieve this interface, we can see from figure 1-4, there are more than a hundred classes to achieve the Closeable interface, which means that in the closure of more than one hundred types of objects, you need to write put code in the finally method. This is terrible! You can endure, anyway, the small people is not can not help! So the young people are going to play his intelligence to solve this problem, since all is to achieve the Closeable interface, so as long as I build a method to close these objects can not be it? Said the dry dry, so the small people write down as follows:

Figure 1-4 3

Public Final Class CloseUtils{

CloseUtils Private () {}

    / * *
* close Closeable object
*@paramCloseable
* /
    Public Static Void CloseQuietly(closeable Closeable) {
        If(Null= closeable) {
            Try{
Closeable.close ();
}Catch(E IOException) {
E.printStackTrace ();
}
}
}
}

We'll see how the code is applied to the above put method:

Public Void Put(URL Bitmap, BMP String) {
FileOutputStream FileOutputStream =Null;
    Try{
FileOutputStream =NewFileOutputStream (cacheDir + URL);
Bmp.compress (CompressFormat.PNG,One hundredFileOutputStream);
}Catch(E FileNotFoundException) {
E.printStackTrace ();
}Final{ly
CloseUtils.closeQuietly (fileOutputStream);
}
}

The code is simple! And the closeQuietly method can be applied to all kinds of objects that can be closed, so that the code can be reused. The basic principle of closeQuietly's CloseUtils method is to rely on the Closeable abstraction rather than the concrete implementation (which is not dependent on the inverted principle in the 1.4), and is based on the principle of minimizing dependency. It only needs to know that the object is closed.

Imagine, if you just need to close an object, it is exposed to other interface functions, such as write OutputStream method, which makes more details exposed in front of the client code, not only did not hide the implementation, but also increased the difficulty of using the interface. And through the Closeable interface to be able to close the object abstraction, so that only the client depends on the Closeable on the client can hide other interface information, the client code only need to know that the object can be closed (only close method can be called). ImageCache is the application of the principle of interface isolation, ImageLoader only need to know that the cache object is stored, the interface can be taken from the cache, the other no matter, which makes the specific implementation of the cache memory ImageLoader specific. This is to use the minimization interface to isolate the details of the implementation class, but also to split the huge interface to a more fine-grained interface, which makes our system has a lower coupling, higher flexibility.

Bob (C Martin Robert) in early twenty-first Century will be a single duty, open and close principle, the scale of the principles, interface isolation and dependency inversion (also known as the dependency inversion) 5 principles are defined as the SOLID principle, refers to the 5 basic principles of object-oriented programming. When these principles are applied together, they make a software system more clear, simple, and the maximum embrace change. SOLID is typically used in test driven development, and is an important part of the basic principles of agile development and adaptive software development. After learning from the first 1.5 to 1.1, we find that these principles can eventually be reduced to a few key words: abstract, single responsibility, minimization. So in the actual development process how to balance and to practice these principles, we need in practice in thinking and understanding, is the so-called "learning without thinking is useless. Thought without learning is perilous", only continuous learning, practice, reflection, can in the process of accumulation have a qualitative leap.

6, better scalability - Dmitry principle

The full name of Law is of Demeter, or LOD, which is also called Knowledge Principle (Least). Although the names are different, but the same principle is described: an object should have the least knowledge of other objects. Common ground is told, a class should they need coupling or call the class know the least, inside the class how to realize, how complicated are and the caller or dependence can, a caller or dependent patients only need to know he needs can be, I totally do not concern of. The more closely the relationship between the class and the class, the greater the degree of coupling, the greater the impact on the other class when a class has changed.

Dmitry law also has an English interpretation is: talk to your immedate friends Only, the translation is: only with direct communication. What is called direct friend? Each object is bound to have a coupling relationship with other objects, the coupling between the two objects is a friend relationship, the type of relationship, such as combination, aggregation, dependence, etc..

Light said not to practice very abstract Na, below we will rent as an example to explain the principle of Dmitry.
"Drift" students understand, rent in Beijing, the vast majority are found through the intermediary of the housing. We set the situation as follows: I only request the room area and the rent, the other all regardless, the intermediary will be in line with my request the house to provide for me to be able to. Below we look at this example:

/ * *
* room
* /
Public Class Room{
    Public FloatArea;
    Public FloatPrice;

    Public Room(FloatArea,FloatPrice) {
        This.area = area;
        This.price = price;
}

    @Override
    PublicStringToString(1)
        Return "[area= Room"+ area +"Price="+ price +"]";
}

}

/ * *
Intermediary
* /
Public Class Mediator{
MRooms List<Room> =NewArrayList<Room> ();

    Public Mediator(1)
        For(inti =0I; "FiveI++) {
MRooms.add (New(RoomFourteenI, (Fourteen+ * I)150));
}
}

    PublicList<Room>GetAllRooms(1)
        ReturnMRooms;
}
}


/ * *
* tenants
* /
Public Class Tenant{
    Public FloatRoomArea;
    Public FloatRoomPrice;
    Public Static Final FloatDiffPrice =100.0001F;
    Public Static Final FloatDiffArea =0.00001F;

    Public Void RentRoom(mediator Mediator) {
List<Room>rooms = mediator.getAllRooms ();
        For(room Room: rooms) {
            If(isSuitable (room)) {
System.out.println ("Rent the room!"+ room);
                Break;
}
}
}

    Private Boolean IsSuitable(room Room) {
        ReturnMath.abs (roomPrice - room.price) < diffPrice
&&Math.abs (roomArea - room.area) < diffArea;
}
}

From the above code can be seen, Tenant not only rely on the Mediator class, but also need to deal with the Room class frequently. The request of tenants only through the intermediary to find a room for their own, if the test conditions are placed in the Tenant class, then the function of the intermediary is weakened, and lead to a higher Tenant and Room coupling, because Tenant must know a lot about the details of Room. When Room changes, Tenant must also follow the changes. Tenant and Mediator coupling, leads to become entangled in the relationship. This time we need to distinguish who is our real "friend", in our set of circumstances, is clearly Mediator (although not in real life). The structure of the code is shown in Figure 1-5.

Figure 1-5 3

Since it is too serious, we can only be decoupled, first of all, we must be clear that we communicate with our friends, here is the Mediator object. Room related operations must be removed from the Tenant, and these operations should be Mediator:

/ * *
Intermediary
* /
Public Class Mediator{
MRooms List<Room> =NewArrayList<Room> ();

    Public Mediator(1)
        For(inti =0I; "FiveI++) {
MRooms.add (New(RoomFourteenI, (Fourteen+ * I)150));
}
}

    PublicRoomRentOut(FloatArea,FloatPrice) {
        For(room Room: mRooms) {
            If(isSuitable (area, price, room)) {
                ReturnRoom;
}
}
        Return Null;
}

    Private Boolean IsSuitable(FloatArea,FloatPrice, room Room) {
        ReturnMath.abs (price - room.price) < Tenant.diffPrice
Math.abs (room.area - area) < Tenant.diffPrice;
}
}

/**
 * 租