面向对象的设计模式(一)

一、设计模式的概念

什么是好的软件设计?—— 复用!
◆  首先我们要先理解一个问题,什么是 模式? 
每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动。 
◆  设计模式:也就是为了使代码的可复用,减少不必要的劳动;通常情况下,我们讲的设计模式隐含地表示“面向对象设计模式”。(其中 可复用是目标,面向对象是手段,这两点是设计模式的核心。)

二、面向对象的设计模式

变化是复用的天敌!面向对象设计最大的优势 —— 抵御变化!

(一)  “组件协作”模式

现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。

1.  Template Method模板方法

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义(override重写)该算法的某些特定步骤。
初始代码:
//程序库开发人员
class Library {

    //稳定
    public void step1() {
        //...
    }

    //稳定
    public void step3() {
        //...
    }

    //稳定
    public void step5() {
        //...
    }

}
//应用程序开发人员
class Application {

    //变化
    public boolean step2() {
        //...
        return true;
    }

    //变化
    public void step4() {
        //...
    }

    //稳定
    public static void main(String args[]) {


        Library lib = new Library();

        Application app = new Application();

        lib.step1();

        if (app.step2()) {
            lib.step3();
        }

        for (int i = 0; i < 4; i++) {
            app.step4();
        }

        lib.step5();
    }

}
优化代码:
//程序库开发人员
abstract class Library {
    public void run() {//稳定 template method

        step1();
        if (step2()) {//支持变化 ==> 虚函数的多态调用
            step3();
        }

        for (int i = 0; i < 4; i++) {
            step4();//支持变化 ==> 虚函数的多态调用
        }

        step5();
    }


    protected void step1() {//稳定
        //...
    }

    protected void step3() {//稳定
        //...
    }

    protected void step5() {//稳定
        //...
    }

    abstract boolean step2();//变化

    abstract void step4();//变化
}
//应用程序开发人员
class Application extends Library {

    @Override
    protected boolean step2() {
        //... 子类重写实现
        return true;
    }

    @Override
    protected void step4() {
        //... 子类重写实现
    }

    public static void main(String args[]) {

        Library lib = new Application();
        lib.Run();

    }

}
使用Template模式优化后,将本来要写在应用程序代码中算法骨架提前添加到程序库中来,而应用程序开发人员只需要override重写方法即可。
◆  要点总结:
        ●  它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构;
        ●  除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template的典型应用;
        ●  在具体实现方面,被Template调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法。

2.  Strategy策略模式

◆  动机:
        在软件构建过程中,某种对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一种性能负担。如何在运行时根据需要透明的更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
初始代码:
public enum TaxBase {
    CN_Tax,
    US_Tax,
    DE_Tax,
    FR_Tax, //更改
};

public class SalesOrder{

    TaxBase tax;

    public void calculateTax(){

        //...

        switch(tax){
            case CN_Tax:
                //CN***********
                break;
            case US_Tax:
                //US***********
                break;
            case De_Tax:
                //DE***********
                break;
            case FR_Tax:  //更改
                //FR***********
                break
        }


        //....
    }

}
上述代码中,如果要增加一个选项,需要在两处进行更改;
优化代码:
abstract class TaxStrategy{
    public abstract double Calculate(Context context);
}

public class CNTax extends TaxStrategy{

    @Override
    public double Calculate(Context context){
        //......
    }

}

public class USTax extends TaxStrategy{

    @Override
    public  double Calculate(Context context){
        //******
    }
}

public class DETax extends TaxStrategy{

    @Override
    public  double Calculate(Context context){
        //######
    }
}

//扩展
public class FRTax extends TaxStrategy{

    @Override
    public  double Calculate(Context context){
        //######
    }
}



public class SalesOrder{

    TaxStrategy strategy;

    public SalesOrder(TaxStrategy strategy){
        this.strategy=strategy;
    }


    public double CalculateTax(){
        //...
        Context context;

        double val=strategy.Calculate(context);//多态调用
        //...

    }

}
        优化后,好处有两点:1. 只需要扩展一个FRtext选项即可,主题算法是不需要改变的;2. 初始代码中,编译器要编译所有的代码,即使有些case里的选项是用不到的。优化后,利用抽象类的多态性,只有需要的选项才会被实例化进行编译,这样能够节省CPU的应用空间。
◆  模式定义:
        定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用它的客户程序而变化(扩展,子类化)。在上例中,我们用类来封装每一个算法,然后创建一个基类的统一的接口。通过接口,当需要哪一个算法时就调用哪个算法。当需求变更时,我们只需要扩展一个子类即可。其中,客户程序就是SaleOrder()方法,算法改变,但客户程序不需要改变。
◆  要点总结:
        ●  Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便的根据需要在各个算法之间切换;
        ●  Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦和。含有很多条件判断语句的代码通常需要Strategy模式;
        ●  如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。

3.  Observer观察者模式

◆  动机:
        在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
public class MainActivity extends AppCompatActivity {

    private Button mAppendButton;
    private EditText mEditText;
    private TextView mLabelText;

    private int count=0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mAppendButton = (Button) findViewById(R.id.appendButton);
        mEditText = (EditText) findViewById(R.id.contentEdit);
        mLabelText = (TextView) findViewById(R.id.countText);


        //订阅通知
        mEditText.addTextChangedListener(textWatcher);

        //取消订阅
        //mEditText.removeTextChangedListener(textWatcher);

        mAppendButton.setOnClickListener(clickListener);


    }


    OnClickListener clickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            String content = mEditText.getText().toString().trim();
            //文本框内容处理
            content = content + Integer.toString(count);
            count++;
            mEditText.setText(content);
            mEditText.setSelection(content.length());//光标置于末尾
        }
    };


    TextWatcher textWatcher = new TextWatcher() {

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            Log.i("BeforeTextChanged:", s.toString() );
        }


        public void onTextChanged(CharSequence s, int start, int before, int count) {

            Log.i("OnTextChanged:", s.toString() );
        }

        public void afterTextChanged(Editable s) {
            String count = Integer.toString(s.length());
            mLabelText.setText(count);
        }
    };

}
        上例中,我们对EditText添加了TextWatcher,查看源代码可以看到,这个TextWatcher是被添加到一个TextWatcher数组中,这里可以添加多个观察者。并重写了TextWatcher的三个方法。当EditText的内容发生改变时,就会通知依赖它的对象(MainActivity)执行相应的方法。上面代码中定义一个TextWatcher这一块,就是一个Observer观察者对象。需求变更时,我们也只需要改变这一块代码即可。上例中,还有一个观察者对象,就是Button的OnClickListener对象,它只观察一个对象,所以没有观察者列表,这是Observer的一个弱化版。
◆  模式定义:
        定义对象间一种一对多的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
◆  要点总结:
        ●  使用面向对象的抽象,Observer模式使得我们可以独立地改变目标和观察者,从而使二者的依赖关系达至松耦合;
        ●  目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播;
        ●  观察者自己决定是否需要订阅通知,目标对象(例子中的MAinActivity)对此一无所知;
        ●  Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值