写点什么

第三周设计模式总结

用户头像
leo
关注
发布于: 2020 年 11 月 08 日
第三周设计模式总结

简单工厂模式


又叫做静态工厂方法(Static Factory Method)


简单工厂模式的实质是由一个工厂类根据传入的参数动态决定应该创建哪一个产品类


Spring 中的 BeanFactory 就是简单工厂模式的体现,根据传入一个唯一的标识来获得 bean 对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。如下配置,就是在 HelloItxxz 类中创建一个 itxxzBean

<beans>  <bean id="singletonBean" class="com.itxxz.HelloItxxz">     <constructor-arg>       <value>Hello! 这是singletonBean</value>     </constructor-arg> </bean> <bean id="itxxzBean" class="com.itxxz.HelloItxxz"  singleton="false">   <constructor-arg>       <value>Hello! 这是itxxzBean! </value>   </constructor-arg> </bean></beans>
复制代码

单例模式

懒汉式


线程不安全实现

public class Singleton {  private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
复制代码

双重检查模式实现

public class Singleton {  private static volatile Singleton singleton; 
private Singleton() {}
public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; }}
复制代码


饿汉式

public class Singleton {  private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return instance; }}
复制代码


枚举实现

public enum Singleton {  INSTANCE;}
复制代码


策略模式 ( Strategy Pattern )

定义

该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。

优点


  1. 使用策略模式可以避免使用多重条件语句

  2. 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码

  3. 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的

  4. 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法

  5. 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离

缺点


  1. 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类

  2. 策略模式造成很多的策略类

实现

继承实现

定义一个抽象类,强制子类实现该方法

这种实现,对父类对子类不一定是透明的,如果父类提供了默认的实现,子类需要了解实现的细节,再决定是否重写

public abstract class Action {  // 也可以将该方法设置成抽象方法, 强迫子类来实现该方法  public void execute() {    // 提供一个默认的实现  }}
public class ActionModelA extends Action { public void execute() { aStyleBrake();// A 风格的行为 }}
public class ActionModelB extends Action { public void execute() { bStyleBrake(); // B 风格的行为 }}
复制代码


组合实现


这种实现是透明的,只需要改变对象的引用就可以改变其行为。


public interface IBrakeBehavior {  void execute();}
public class AStyleBrake implements IBrakeBehavior { public void execute() { aStyleBrake(); // A 风格的行为 }}
public class BStyleBrake implements IBrakeBehavior { public void execute() { bStyleBrake(); // B 风格的行为 }}
public class Action { protected IBrakeBehavior brakeBehavior;
public void execute() { brakeBehavior.execute(); }
public void setBrakeBehavior(final IBrakeBehavior brakeType) { this.brakeBehavior = brakeType; }}
复制代码


最后通过工厂类,根据运行的参数选择出对应的实现

Action action  = ActionFactory.createAction(String parameters);   action.execute();
复制代码


只有在策略选择里有条件选择语句,其他地方不出现。


如上述的createAction()方法

适配器模式 ( Adapter Pattern )


定义


将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。分为两种模式:


  • 类适配器模式:适配器与适配者之间是继承(或实现)关系

  • 对象适配器模式:适配器与适配者之间是关联关系

前者的耦合度比后者高,且要求开发了解现有组件库中的相关组件的内部结构,应用相对较少些。


优点


  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。

  • 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。

  • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

类适配器模式优点:


由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。


对象适配器模式优点:


同一个适配器可以把适配者类和它的子类都适配到目标接口。


缺点


类适配器模式缺点:


对于 Java 等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。


对象适配器模式缺点:


与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。


实现


角色


  • Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。

  • Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对 Adaptee 和 Target 进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承 Target 并关联一个 Adaptee 对象使二者产生联系。

  • Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。

类适配器


首先有一个已存在的将被适配的类:


public class Adaptee {    public void adapteeRequest() {        System.out.println("被适配者的方法");    }}
复制代码

定义一个目标接口:

public interface Target {    void request();}
复制代码

如果通过一个适配器类,实现 Target 接口,同时继承了 Adaptee 类,然后在实现的 request() 方法中调用父类的 adapteeRequest() 即可实现


public class Adapter extends Adaptee implements Target{    @Override    public void request() {        //...一些操作...        super.adapteeRequest();        //...一些操作...    }}
复制代码

对象适配器


对象适配器与类适配器不同之处在于,类适配器通过继承来完成适配,对象适配器则是通过关联来完成,这里稍微修改一下 Adapter 类即可将转变为对象适配器


public class Adapter implements Target{    // 适配者是对象适配器的一个属性    private Adaptee adaptee = new Adaptee();
@Override public void request() { //... adaptee.adapteeRequest(); //... }}
复制代码


装饰器模式


在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。我们以往在 spring 和 hibernate 框架中总是配置一个数据源,因而sessionFactorydataSource属性总是指向这个数据源并且恒定不变,所有 DAO 在使用sessionFactory的时候都是通过这个数据源访问数据库。


但是现在,由于项目的需要,我们的 DAO 在访问sessionFactory的时候都不得不在多个数据源中不断切换,问题就出现了:如何让sessionFactory在执行数据持久化的时候,根据客户的需求能够动态切换不同的数据源?我们能不能在 spring 的框架下通过少量修改得到解决?是否有什么设计模式可以利用呢?


首先想到在 spring 的applicationContext中配置所有的dataSource。这些dataSource可能是各种不同类型的,比如不同的数据库:Oracle、SQL Server、MySQL 等,也可能是不同的数据源:比如 apache 提供的org.apache.commons.dbcp.BasicDataSource、spring 提供的org.springframework.jndi.JndiObjectFactoryBean等。然后sessionFactory根据客户的每次请求,将dataSource属性设置成不同的数据源,以到达切换数据源的目的。


spring 中用到的包装器模式在类名上有两种表现:一种是类名中含有 Wrapper,另一种是类名中含有 Decorator


基本上都是动态地给一个对象添加一些额外的职责


模板方法模式


定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。


Template Method 模式一般是需要继承的。这里想要探讨另一种对 Template Method 的理解。spring 中的JdbcTemplate,在用这个类时并不想去继承这个类,因为这个类的方法太多,但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接,那么我们怎么办呢?我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码,而且这段代码会用到JdbcTemplate中的变量。怎么办?那我们就用回调对象吧。


在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,我们去实现这个方法,就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate,从而完成了调用。这可能是 Template Method 不需要继承的另一种实现方式。


以下是一个具体的例子:


JdbcTemplate中的 execute 方法



发布于: 2020 年 11 月 08 日阅读数: 49
用户头像

leo

关注

还未添加个人签名 2018.03.23 加入

还未添加个人简介

评论

发布
暂无评论
第三周设计模式总结