浅谈开发中常用的设计模式

Posted showCar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈开发中常用的设计模式相关的知识,希望对你有一定的参考价值。

设计模式在开发中占很重要的地位。在大型项目中使用好设计模式往往会取得事半功倍的效果。本篇博客就介绍下几种在开发中常用到的设计模式。

设计原则

先看下一些约定俗成的设计原则,其实要遵守以下所有原则很难,但开发过程中还是要有这样的意识。

  • 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。(封装变化)
  • 针对接口编程,而不是针对实现编程。
  • 多用组合,少用继承:用组合建立的系统具有很大的弹性,不仅可以将算法封装成类,也可以在运行时动态地改变行为。总结一句话就是,有一个比是一个更好。
  • 为交互对象之间的松耦合设计而努力。
  • 对扩展开放,对修改关闭。(装饰者是很好的体现)
  • 要依赖抽象,不要依赖具体类。这就是依赖倒置原则。它更强调的是抽象,不能让高层组件依赖低层组件。
  • 最少知识原则:只和你的密友谈话。就是说当你在设计一个系统,不管任何对象,你都要注意它所交互的类有哪些。不要让太多的类藕合在一起。
  • 单一模式:一个类应该只有一个引起变化的原因。

模式介绍

策略模式

策略模式定义是:定义算法族,分别封装起来,让它们之间可以互相替换,算法的变化独立于使用算法的客户。
我们来模拟一种情形来理解这句话。有一群鸭子,有各种颜色的鸭,他们有的会飞,有的不会飞,飞的姿态也更不相同。此时如果在每只鸭子里分别定义飞的姿态,那有成千上万中鸭子的时候就会累死。这时我们考虑使用设计模式来实现下它。
设计原则中第一条:找出应用中可能需要变化之处,把它们独立出来。当然这里我们独立的就是会变化的飞行为。
设计模式第二条:针对接口编程,而不是针对实现编程。所以到这里我们写出如下飞的代码:

public interface FlyBehavior 
    public void fly();

定义了接口类,再定义实现类,会简单,只定义会飞和不会飞行为:

public class NoFly implements FlyBehavior 

    @Override
    public void fly() 
        // TODO Auto-generated method stub
        System.out.println("this duck can not fly");
    



public class CanFly implements FlyBehavior

    @Override
    public void fly() 
        // TODO Auto-generated method stub
        System.out.println("this duck can fly");
    

以上就是针对接口编程,那它有什么好处呢,继续往下看。
设计原则第三条:多用组合,少用继承。那我们也来运用下。定义鸭子的抽象类:

public abstract class Duck 
    FlyBehavior flyBehavior;

    public abstract void disply();

    public  void performFly()
        flyBehavior.fly();
    

    public FlyBehavior getFlyBehavior() 
        return flyBehavior;
    
    public void setFlyBehavior(FlyBehavior flyBehavior) 
        this.flyBehavior = flyBehavior;
    

其中它有一个FlyBehavior对象,组合了飞的行为,典型的“有一个“而不是”有一个“。
好了,接下来就是实体鸭子, 只要继承超类就可以了。

public class RedDuck extends Duck

    public RedDuck() 
        // TODO Auto-generated constructor stub
        flyBehavior = new NoFly();//默认不会飞

    
    @Override
    public void disply() 
        // TODO Auto-generated method stub
        System.out.println("the color is red");
    

红鸭不会飞,再来一只黑鸭会飞:

public class BlackDuck extends Duck

    public BlackDuck() 
        // TODO Auto-generated constructor stub
        flyBehavior = new CanFly();//默认不会飞

    
    @Override
    public void disply() 
        // TODO Auto-generated method stub
        System.out.println("the color is black");
    

最后我们来调用一下:

public class Main 
    public static void main(String[] args)
        Duck duck = new RedDuck();
        duck.performFly();
        duck.disply();
        duck.setFlyBehavior(new CanFly());
        duck.performFly();
        System.out.println("-----------------");
        Duck duck2 = new BlackDuck();
        duck2.performFly();
        duck2.disply();
        duck2.setFlyBehavior(new NoFly());
        duck2.performFly();
    

这就是大名鼎鼎的策略模式。好处己经非常明显了,要什么飞行行为只要在运行时进行替换就可以了。这种模式的好处:实现不会被绑死在子类中,使用接口,可以运行时替换。看上它的UML图:

观察者模式

定义了对象之间的一对多依赖,这样一来,当一个对象改变时,它的所有依赖者都会收到通知并自动更新。
模拟场景的话很简单,就是比如图书馆,你在图书馆借书,相当于你就是图书馆的一个观察者,当图书馆有新闻发布时你就会收到通知。
先看一下它的UML图:

从观察人员入手:

public interface Observer 

    public void update(String name);
    public void disConnect();

只需要两个方法,有消息更新后会通知你(update)。如果你觉得烦也可以取消观察。新建实现类小明:

public class XiaoMingObserver implements Observer
    String bookName;
    private Subject subject;
    public XiaoMingObserver(Subject subject) 
        // TODO Auto-generated constructor stub
        this.subject = subject;
        subject.registerObserver(this);
    
    @Override
    public void update(String name) 
        // TODO Auto-generated method stub

        System.out.println ("i am xiaoMing,the new book is "+name);
    
    @Override
    public void disConnect() 
        // TODO Auto-generated method stub
        this.subject.removeObserver(this);
    

小明拥有图书证(有一个Subject 对象),subject注册了它,它就成了一个观察者,看下subject:

public interface Subject 
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();

实现三个功能,注册观察者,删除观察者,通知变化。可见它要拥有观察者对象。看下具体的实现。

public class BookSubject implements Subject 
    private String bookName;
    ArrayList<Observer> aList; 
    public BookSubject() 
        // TODO Auto-generated constructor stub
        aList = new ArrayList<Observer>();
    
    @Override
    public void registerObserver(Observer o) 
        // TODO Auto-generated method stub
            aList.add(o);

    

    @Override
    public void removeObserver(Observer o) 
        // TODO Auto-generated method stub
        if(aList.contains(o))
            aList.remove(o);
        
    

    @Override
    public void notifyObservers() 
        for(Observer observer :aList)
            if(observer instanceof XiaoGaoObserver)
                bookName = "java编程思想";
            else
                bookName = "c++编程思想";
            

            observer.update(bookName);

    
    

registerObserver添加观察者到List中。发布通知也就是调用观察者的Notify方法。观察者在android源码中就很我地方体现,如Adapter中就是观察数据变化就更改界面。以后有时间写下Adapter的源码分析。

工厂模式

工厂模式有三种,个人感觉工厂模式还是比较复杂的。一步步讲吧,最后会把源码附上。

1.简单工厂模式

简单工厂模式最好理解,平时用得也很多。简单工厂模式主要是在初始化对象进行解耦合,工厂模式封装了创建对象的细节。一般是静态方法。但使用静态方法有一个缺点,就是无法通过继承来改变对象创建过程。
我们来模拟一个场景,假设我们在卖肠粉(最爱肠粉了。。。)。我们要做很多口味,这时不能做一种口味就new一个肠粉,因为做肠粉只有前面加料时步骤不一样,后面的切跟蒸都是一样的。先看上UML图:

所以我们用简单工厂模式写出以下代码:

public class SimpleChangfenStore 
    SimpleFactory mFactory = null;
    public SimpleChangfenStore(SimpleFactory factory)
        this.mFactory = factory;
    
    public void orderChangfen(String tag)
        Changfen mChangfen = null;
        mChangfen = mFactory.createChangfen(tag);
        mChangfen.prepare();
        mChangfen.bake();
        mChangfen.cut();
        System.out.println("------finish one-------");
    

createChangfen的作用就是用于抽取出来专门创建肠粉对象,这样做的好处是可以防止你每次添加一种口味的肠粉都要修改这个类。看下它的代码:

public class SimpleFactory 
    public Changfen createChangfen(String tag) 
        Changfen changfen = null;
        if(tag.equals("vegetable"))
            changfen = new VegetableChangfen();
    else if(tag.equals("meat"))
        changfen = new MeatChangfen();
    
    return changfen;
    

根据tag创建不同的肠粉。最后来看下如何使用:

public class SimpleMain 
    public static void main(String[] args)
        SimpleFactory factory = new SimpleFactory();
        SimpleChangfenStore store = new SimpleChangfenStore(factory);
        store.orderChangfen("meat");
        store.orderChangfen("vegetable");
    

很简单,只要知道factory专门用来创建对象的就可以了。看下输出结果:

接下来看下工厂模式。

工厂模式

工厂模式:把创建changfen分为子类中,定义一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。
其实也很好理解,先看下UML图:

回到我们的肠粉店,现在我们的生意很好,要开分店啦,很开心。在深圳和汕头更来一家店。那深圳和汕头创建的店对象肯定是不同的嘛。所以类的实例化在到子类中,让子类自己来创建。为此,我们的店要把创建对象的方法定义成抽象的。

public abstract class ChangfenStore 
    public abstract Changfen createChangfen(String tag);
    public void orderChangfen(String tag)
        Changfen mChangfen = null;
        mChangfen = createChangfen(tag);
        mChangfen.prepare();
        mChangfen.bake();
        mChangfen.cut();
        System.out.println("------finish one-------");
    

createChangfen定义成抽象的了,要由子类来实现,看下深圳的子类:

public class SZStore extends ChangfenStore

    @Override
    public Changfen createChangfen(String tag) 
        // TODO Auto-generated method stub
        Changfen changfen = null;
        if(tag.equals("vegetable"))
            changfen = new SZVegetableChangfen();
    else if(tag.equals("meat"))
        changfen = new SZMeatChangfen();

    
    return changfen;
    

看吧,深圳用的是深圳的肉和菜,小看一眼:

public class SZVegetableChangfen extends Changfen

    @Override
    public void prepare() 
        // TODO Auto-generated method stub
        System.out.println("i am in Shenzhen,i like the cabbage,so i add the cabbage");
    

这样就实现了工厂模式。看下如何使用:

public class Main 
    public static void main(String[] args)
        ChangfenStore SZstore = new SZStore();
        SZstore.orderChangfen("meat");
        SZstore.orderChangfen("vegetable");

        ChangfenStore STstore = new STStore();
        STstore.orderChangfen("meat");
        STstore.orderChangfen("vegetable");
    

输出如下:

好啦 ,接下来讲讲抽象工厂方法啦。

抽象工厂方法

抽象工厂模式:提供一个接口,用于创建或依赖对象的家族,而不需要明确指定具体类。它提供了一个原料的生产工厂,原料的生产对客户不可见。
不太好理解,其实就是创建一些依赖对象的原料。继续看我们的肠粉。我们深圳店和汕头店加的原料肯定是不同的,即使是用鱼,那鱼的种类也不一定相同。用一句话说就是深圳店和汕头店要有自己的原料工厂。
原料嘛,就要有原料工厂,先看下原料工厂:

public abstract class AbstractChangfenFactory 
    public abstract Flour createFlour();
    public abstract Sauce createSauce();
    public abstract Seasoning createseasoning();

它是一个抽象类。肠粉要加酱加料等。具体加哪些酱哪些料,看具体实现类:

public class SZChangfenFactory extends AbstractChangfenFactory
    @Override
    public Flour createFlour() 
        // TODO Auto-generated method stub
        return new SZFlour();
    

    @Override
    public Sauce createSauce() 
        // TODO Auto-generated method stub
        return  new SZSauce();
    

    @Override
    public Seasoning createseasoning() 
        // TODO Auto-generated method stub
        return new SZSessioning();
    

看吧,是深圳特有的SZSauce,SZFlour等。这些都是对象,本例子只是简单的打印一句话,这里就不贴出来了,具体就不贴出来了。要记得汕头也有自己的原料STSauce等。
原料都买好了,开始做肠粉吧:

public abstract class AbstractChangfen
    protected Sauce mSauce = null;
    protected Flour mFlour = null;
    protected Seasoning mSeasioning = null;

    public abstract void prepare();
    public void bake()
        System.out.println("after prepare,the Changfen should be bake");
    
    public void cut()
        System.out.println("after bake,the Changfen should be cut");
    

看下深圳是怎么做的,来到深圳分店视察:

public class STStore extends ChangfenStore

    @Override
    public AbstractChangfen createChangfen(String tag) 
        AbstractChangfen changfen = null;
        AbstractChangfenFactory factory;
        factory = new STChangfenFactory();
        if(tag.equals("vegetable"))
            changfen = new STAbstractVegetableChangfen(factory);
    else if(tag.equals("meat"))
        changfen = new STAbstractMeatChangfen(factory);

    
    return changfen;
    

深圳人嘛,要记得选择深圳的原料工厂哦。选其中的做肉肠粉的代码来看一看:

public class STAbstractMeatChangfen extends AbstractChangfen

    private AbstractChangfenFactory mFactory = null;
    public  STAbstractMeatChangfen(AbstractChangfenFactory factory) 
        // TODO Auto-generated constructor stub
        this.mFactory = factory;
    
    @Override
    public void prepare() 
        // TODO Auto-generated method stub
        this.mSauce = this.mFactory.createSauce();
        this.mFlour = this.mFactory.createFlour();
        System.out.println("i am in ShanTou factory,i like meat,the sause is "+this.mSauce.print()+",the flour is "+this.mFlour.print());

    

到此就一目了然了,深圳用深圳的原料,汕头用汕头的原料。输出结果如下:

到此工厂模式就讲完了。看下UML图。画得比较复杂,细心看,能看懂的。

篇幅关系,还有几个常用设计模式下篇再总结。先到这吧。

以上是关于浅谈开发中常用的设计模式的主要内容,如果未能解决你的问题,请参考以下文章

浅谈面向对象开发原则:高内聚,低耦合

测试开发要懂的设计模式知识

浅谈常用接口中的幂等设计

浅谈UML中常用的几种图——用例图

浅谈UML中常用的几种图——用例图

浅谈敏捷开发中的架构设计!(干货)