Java设计模式

1.1设计模式概述

        设计模式可以使人们跟家简单方便的复用成功的设计和体系结构。将已证实的技术方案总结成设计模式,也会使其他开发证更加容易理解其设计思路。设计模式是可复用的面向对象软件的基础,帮助开发者做出有利于系统复用的选择,避免损害系统复用性的设计。

        目前所说的设计模式通常是指GoF设计模式。一共有23种设计模式。

        这23中设计模式有两种分类方式:

        (1)根据目的划分,即根据设计模式是用于完成何种工作来划分。这种方式可分为创建型模式、结构型模式和行为型模式3种:

创建型模式:用于描述“如何创建对象”,其主要特点是“将对象的创建与使用分离。

结构型模式:用于描述如何将类或对象按某种布局组成更大的结构。

行为型模式:用于描述类或对象之间如何相互协作,共同完成单个对象无法独立完成的任务以及如何分配职责。

        (2)根据作用范围划分,即根据设计模式主要作用于类上还是主要作用于对象上来划分。这种方式可分为类模式和对象模式两种:

类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。

对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时是可以
变化的,更具动态性。

1.2 软件可复用问题和面向对象设计原则

 众所周知,在软件开发和使用的过程中,需求是经常变化的。面对这些变化,设计不足的软件往往
难以修改甚至要重新设计。大多数的软件应用是由多个类通过彼此合作才能实现完整的功能。对于组件化开发的软件来说,组件之间会存在各种依赖关系。例如,在 A 类的方法中,调用了 B 类对象的方法以完成特定的功能,我们就说 A 类依赖于 B 类。类与类之间的依赖关系增加了程序开发的复杂程度,一个类的变更,可能会对正在使用该类的所有类产生影响。以常见的业务层调用数据访问层的操作为例,代码通常如下所示

/**
 * 新闻模块的Dao接口
 */
public interface NewsDao {
    /**
     * 保存新闻的方法
     */
    public void sace(New news);

}

/**
 * 新闻模块的Dao实现类
 */
public class NewDaosImpl implements NewDao {
    private Logger logger = Logger.getLogger(NewsDaoImpl.class);
    public void save("保存新闻信息到数据库");
    ....//省略数据库操作代码
}

/**
 * 新闻模块业务类
 */
public class NewsServiceImpl implements NewsService{
    //实例化所依赖的NewsDao对象
    private NewsDao dao = new NewsDaoImpl();
    public void addNews(News news){
        //调用NewsDao的方法保存新闻信息
        dao.save(news);
    }
}

以上代码中,NewsServicelmpl 对 NewsDao 接口存在依赖关系,并且与其实现类NewsDaolmpl耦合在一起。此类常见的代码其实存在一个严重问题,即如果因为需求变化需要替换 NewsDao 的实现类将导致 NewsServicelmpl 中的代码也要进行修改。由此不难想象,如果程序中比较基础的模块发生变化将导致该模块的所有调用者都要修改代码,影响了其他模块的重用。如此,程序将难以扩展和维护,甚至难以开发、测试。
对于如何设计易于维护和扩展的软件系统,面向对象的软件设计提出了几大原则。这些原则可以用来检验软件系统设计的合理性,也被设计模式所遵循

1.单一职责原则

单一职责原则规定一个类应该有且仅有一个引起它变化的原因,简单来说,一个类应该只负责一个
职责,否则。类应该被拆分。
该原则提出一个类不应该承担太多职责。如果一个类承担了太多的职责,至少存在以下两个缺点(1)一个职责的变化可能会影响这个类实现其他职责的能力,或者引发其他职责故障
(2)当客户需要该类的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余或
风险。

2.开闭原则

开闭原则是面向对象设计出最基砂的设计原则,开闭原则规定一个软件实体,如类,模块和函数应读对扩展开放,对修改关闭。其意思是,在程序需要进行拓展的时候,不能通过修改已有的代码实现安化,而应该通过扩展软件实体的方式实现,如根据需求重新派生一个实现类。想要达到这样的效果这就需要使用接口,面向接口编程。在软件的生命周期内,因为变化、升级和维护等原因而对软件原有代码进行修改,可能会向原有代码中引入错误,也可能不得不对原有代码整个进行重构,并且原有代码修改后还要重新进行测试.

3.里氏替换原则

里氏替换原则是面向对象设计的基本原则之一,是继承复用的基石。该原则规定所有引用基类的地方必须能透明地使用其子类的对象。简单来说,所有使用基类码的地方,如果换成子类对象还能够正常运行,则满足这个原则:否则就是继承关系有问题,应该取消原来的继承关系,重新设计它们之间的关系。这个原则可以用来判断继承关系是否合理。

4.依赖倒置原则

依赖倒置原则的核心思想是: 依赖于约定而不依赖于具体实现,即面向接口编程。对象的依赖关系有3种传递方式。
(1) 通过构造方法传递依赖对象,即构造方法的参数是需要依赖的接口类型。
(2) 通过 setter 方法传递依赖对象,即 setter 方法的参数是需要依赖的接口类型
(3) 接口声明依赖,即接口方法的参数是需要依赖的接口类型。
如果开闭原则是面向对象设计的目标,那么依赖倒置原则就是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。

5.接口隔离原则

接口隔离原则要求尽量将庞大臃肿的接口拆分成更小、更具体的接口,让接口中只包含客户感兴趣的方法。客户不应该被迫去依赖他不使用的方法,一个类对另一个类的依赖应该建立在最小的接口上要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用否则,很多实现类被迫去实现它们不需要的方法。
接口隔离原则和单一职责原则都是为了提高类的内聚性,降低它们之间的耦合度,但两者是不同的单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离.

单一职责原则主要是约束类,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口主要针对抽象和程序整体框架的构建。

6.迪米特法则

迪米特法则又称为最少知道原则,是指一个软件实体应当尽可能少地与其他实体发生相互作用。具体来讲,被依赖的类应尽量将复杂逻辑封装在类的内部,不对外泄露任何中间信息,使客户对中间过程中的其他实体保持最少的了解,从而减少不必要的依赖,降低耦合。

7.合成复用原则

合成复用原则是指:尽量使用组合/聚合的方式,而不是继承关系达到软件复用的目的继承复用是类型的复用,必须具备 is-a 关系才可通过继承方式进行复用,且从基类继承而来的实现是静态的,不可能在运行期间发生变化,因此没有足够的灵活性。
而合成复用是 has-a 关系,将已有对象纳入到新对象中使之成为新对象的一部分,因此新对象可以调用已有对象的功能。使用合成复用方式,新对象可以在运行期间动态地引用与成分对象类型相同的实现

1.3设计模式的应用

1.3.1工厂方法模式

1. 工厂方法模式分为三种:普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
2. 多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
3. 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

1. 普通工厂模式

建立一个工厂类,对实现了同一接口的一些类进行实例的创建。

interface Sender {
    void Send();
}

class MailSender implements Sender {

    @Override
    public void Send() {
        System.out.println("This is mail sender...");
    }
}

class SmsSender implements Sender {

    @Override
    public void Send() {
        System.out.println("This is sms sender...");
    }
}

public class FactoryPattern {
    public static void main(String[] args) {
        Sender sender = produce("mail");
        sender.Send();
    }
    public static Sender produce(String str) {
        if ("mail".equals(str)) {
            return new MailSender();
        } else if ("sms".equals(str)) {
            return new SmsSender();
        } else {
            System.out.println("输入错误...");
            return null;
        }
    }
}

2. 多个工厂方法模式

该模式是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

interface Sender {
    void Send();
}

class MailSender implements Sender {

    @Override
    public void Send() {
        System.out.println("This is mail sender...");
    }
}

class SmsSender implements Sender {

    @Override
    public void Send() {
        System.out.println("This is sms sender...");
    }
}

class SendFactory {
    public Sender produceMail() {
        return new MailSender();
    }

    public Sender produceSms() {
        return new SmsSender();
    }
}

public class FactoryPattern {
    public static void main(String[] args) {
        SendFactory factory = new SendFactory();
        Sender sender = factory.produceMail();
        sender.Send();
    }
}

3. 静态工厂方法模式

将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

interface Sender {
    void Send();
}

class MailSender implements Sender {

    @Override
    public void Send() {
        System.out.println("This is mail sender...");
    }
}

class SmsSender implements Sender {

    @Override
    public void Send() {
        System.out.println("This is sms sender...");
    }
}

class SendFactory {
    public static Sender produceMail() {
        return new MailSender();
    }

    public static Sender produceSms() {
        return new SmsSender();
    }
}

public class FactoryPattern {
    public static void main(String[] args) {
        Sender sender = SendFactory.produceMail();
        sender.Send();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值