声明:迁移自本人CSDN博客https://blog.csdn.net/u013365635

我们总是需要一些新的思路来引导我们的观念,网上关于设计模式的文章太多,本设计模式讲解系列试着挖掘一些新的思路。这篇总纲性的文章希望对读者记忆、理解各种设计模式有一定的帮助。

设计模式中通用的东西
尽管设计模式的种类繁多,但是我们还是需要抓住一些本质的,通用的东西,如果让我来说,这些本质的通用的东西就是接口(在不同语言中可能有不同的实现,如C++中没有接口的概念,但是有抽象函数、抽象类的概念)。
设计模式作为程序设计中的架构,本质上也离不开数据和数据操纵,只是在操纵数据上有更多大师总结出的一般性的通用的实践证明对程序维护拓展有益的结构。这些结构实现中最重要元素的是什么?是接口。
几乎所有的设计模式都可以顺着这条思路进行理解。以Java实现设计模式为例,类中封装了数据,现在需要访问类中的数据,而且要能在具体类变化的时候仍然能够灵活访问到,实现的方式不就是接口吗。有了接口,就有了具体类对外提供功能的通道,而接口中的参数可以用具体类中的数据来填充。
因此,接口在设计模式中至少有2种用途:屏蔽各种具体类及类方法的具体实现,使接口的整个实现/继承树与其他实现/继承树之间的关系变得简单。

接口的本质什么?是抽象。

下面以策略模式为例,实例说明上面的观点。一个简单的策略模式,其实可以直接从Java接口 Comparator开始,鉴于Comparator的接口比较多,这里就自己重新定义一个了。

step1:

package com.designpattern.strategy;

public interface ICompareStrategy<T>
{
    //是不是感觉和Java自带的interface Comparator很像,Java中的Comparator本来就是可以用来实现自定义的比较策略的。
    int compare(T o1, T o2);
}

step2:

package com.designpattern.strategy;
/**
 * 策略实现类,价格优先策略类
 */
public class ComparePrice implements ICompareStrategy<Product>
{
    @Override public int compare(Product o1, Product o2)
    {
        //注意,这里逻辑要反过来,价格更实惠的按个优先,保持正常逻辑,这里也体现出了策略模式可以屏蔽实现,内部随便我们怎么改动
        return -(o1.getPrice() - o2.getPrice());
    }
}

step3:

package com.designpattern.strategy;

/**
 * 策略实现类,质量优先策略类
 */
public class CompareQualityIndex implements ICompareStrategy<Product>
{
    @Override public int compare(Product o1, Product o2)
    {
        return o1.getQualityIndex() - o2.getQualityIndex();
    }
}

step4:

package com.designpattern.strategy;
/**
 * 策略使用类,产品选择器
 */
public class BetterOneChooser
{
    private ICompareStrategy iCompareStrategy;

    public BetterOneChooser(ICompareStrategy iCompareStrategy)
    {
        this.iCompareStrategy = iCompareStrategy;
    }

    public void chooseBetterOne(Product p1, Product p2)
    {
        System.out.println(String.format("%s is better one for you",
            iCompareStrategy.compare(p1, p2) > 0 ? p1.getName() : p2.getName()));
    }
}

step5:

package com.designpattern.strategy;
/**
 * 策略作用对象,产品类
 */
public class Product
{
    private String name;

    private int price;

    private int qualityIndex;

    public Product(String name, int price, int qualityIndex)
    {
        this.name = name;
        this.price = price;
        this.qualityIndex = qualityIndex;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public int getPrice()
    {
        return price;
    }

    public void setPrice(int price)
    {
        this.price = price;
    }

    public int getQualityIndex()
    {
        return qualityIndex;
    }

    public void setQualityIndex(int qualityIndex)
    {
        this.qualityIndex = qualityIndex;
    }
}

step6:

package com.designpattern.strategy;

public class TestStragetyPattern
{
    public static void main(String[] args)
    {
        ICompareStrategy pricePriority = new ComparePrice();
        ICompareStrategy qualityIndexPriority = new CompareQualityIndex();

        BetterOneChooser chooser1 = new BetterOneChooser(pricePriority);
        BetterOneChooser chooser2 = new BetterOneChooser(qualityIndexPriority);

        Product p1 = new Product("华为手机", 2000, 4);
        Product p2 = new Product("苹果手机", 3000, 5);

        chooser1.chooseBetterOne(p1, p2);
        chooser2.chooseBetterOne(p1, p2);
    }
}

运行输出:
华为手机 is better one for you
苹果手机 is better one for you

接口往下屏蔽了具体的实现,所有和接口实现/继承树关联的类都只需要在自己的类中指定接口而不需要指定具体实现。接口参数使用泛型,可以传递任何你想想传递的数据,从而实现了对其他类数据的引用,实现具体的策略,就好比,你甚至可以直接比较产品名字,看哪个顺眼买哪个。如果不能抽象出接口的概念,设计模式是很难出现的。