设计模式笔记系列 第二篇

        上篇我们笔记了可能都比较熟悉的简单工厂模式、工厂方法模式、抽象工厂模式以及单例模式。这篇咱们继续做笔记,介绍下原型模式、策略模式、适配器模式和模板模式。

        1、原型模式

                (一)、定义

                        用原型实例指定创建对象的类型,并通过拷贝这些原型来创建新的对象。

                (二)、结构

                        

    作为原型的对象,需要声明 Cloneable接口,实现clone接口。通过实现的clone方法,我们可以将原来对象的数据,直接复制一份。但要注意复制后的数据和原来的的数据不是同一个对象。

                (三)、代码演示

/**
 * @Description: 原型模式
 */
public class OriginalMode implements Cloneable{

    private Integer id;
    private String name;
    private kidsMode kidsMode;

    public OriginalMode() {
    }

    public OriginalMode(Integer id, String name, kidsMode kidsMode) {
        this.id = id;
        this.name = name;
        this.kidsMode = kidsMode;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public kidsMode getKidsMode() {
        return kidsMode;
    }

    public void setKidsMode(kidsMode kidsMode) {
        this.kidsMode = kidsMode;
    }

    @Override
    public OriginalMode clone() {
        OriginalMode originalMode = null;
        try {
            originalMode = (OriginalMode) super.clone();
            // 防止属性对象在克隆,跟源对象共享属性对象
            kidsMode keyStroke = this.kidsMode.clone();
            originalMode.setKidsMode(keyStroke);
            return originalMode;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String toString() {
        return "hashcode:"+ this.hashCode() +", OriginalMode{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", kidsMode=" + kidsMode +
                '}';
    }
}


/**
 * @Description: 原型对象引用的属性对象
 */
public class kidsMode implements Cloneable{

    private Integer kidsId;

    private String kidsName;

    public kidsMode(Integer kidsId, String kidsName) {
        this.kidsId = kidsId;
        this.kidsName = kidsName;
    }

    public Integer getKidsId() {
        return kidsId;
    }

    public void setKidsId(Integer kidsId) {
        this.kidsId = kidsId;
    }

    public String getKidsName() {
        return kidsName;
    }

    public void setKidsName(String kidsName) {
        this.kidsName = kidsName;
    }



    @Override
    public String toString() {
        return "hashcode"+ this.hashCode()+ ", kidsMode{" +
                "kidsId=" + kidsId +
                ", kidsName='" + kidsName + '\'' +
                '}';
    }

    @Override
    public kidsMode clone() {
        try {
            return (kidsMode) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}



/**
 * @Description: 原型模式单元测试
 */
public class OriginalModeTest {

    @Test
    public void test(){
        // 原对象数据
        OriginalMode originalMode = new OriginalMode(10, "原型对象名称",
                                        new kidsMode(105, "原型对象属性节点名称"));
        // 克隆后的对象数据
        OriginalMode cloneOriginalMode = originalMode.clone();

        System.out.println(originalMode);
        System.out.println(cloneOriginalMode);

        // 修改原对象属性对象数据
        kidsMode kidsMode = originalMode.getKidsMode();
        kidsMode.setKidsName("修改===》》》原型对象属性节点名称");
        originalMode.setKidsMode(kidsMode);

        System.out.println(originalMode);
        System.out.println(cloneOriginalMode);
    }
}

测试结果

        如上代码,如果要拷贝的对象OriginalMode存在对象属性kidsMode,那么对OriginalMode进行克隆的时候,需要对其属性也进行拷贝。简言之,当原型类中都是不可变对象属性时,对其实现clone接口进行浅拷贝即可;但如果原型类中存在可变对象时,需要进行深拷贝,即还需要对可变对象就行拷贝。

        2、策略模式

                (一)、定义

                        定义一系列的算法,把他们一个个的封装起来,并且使它们可以相互替换,并且算法的变化不会影响到使用算法的用户。

                

                (二)结构

比如,现在有这样个场景,某个产品需要根据不同地域的市场行情,算出产品定价,在向市场发布定价。我们用代码实现下~

                (三)、代码演示
/**
 * @Description: 策略模式
 */
public interface Strategy {

    /**
     * @description: 计算市场定价
     **/
    void calculate();

}


/**
 * @Description: 欧洲市场算法
 */
public class EuropeStrategyImpl implements Strategy {

    @Override
    public void calculate() {
        System.out.println("计算欧洲市场价格.......");
    }
}


/**
 * @Description: 本土市场算法
 */
public class LocalStrategyImpl implements Strategy {

    @Override
    public void calculate() {
        System.out.println("计算本土市场价格..........");
    }
}


/**
 * @Description: 区域市场
 */
public class RegionalMarket {

    private Strategy strategy;

    public RegionalMarket(Strategy strategy) {
        this.strategy = strategy;
    }

    /**
     * @description: 发布市场价格
     *
     * @return: void
     **/
    public void quote(){
        this.strategy.calculate();
        System.out.println("向"+ this.strategy.getClass().getName() +"发布市场价格......");
    }
}


/**
 * @Description: 策略模式单元测试
 */
public class StrategyTest {

    @Test
    public void test(){

        // 根据市场获取对应的算法
        Strategy strategy = new LocalStrategyImpl();

        // 传入算法得到具体的市场
        RegionalMarket regionalMarket = new RegionalMarket(strategy);

        // 市场报价
        regionalMarket.quote();
    }
}

测试结果:

        注意:策略模式的实现和工厂方法模式的实现很相似,但二者其实存在很大的区别。  首先,使用场景不一样:策略模式主要用于在运行中,根据不同的情况选择不同的计算或行为的场景;而工厂方法模式着重在于创建多个相似对象的场景。 其次,对象关系不同:策略模式具体实现的类可以相互替换,而工厂方法模式创建的对象是紧密相关的。他们的关注点也不同:策略模式关注的是对行为的封装,而工厂方法模式关注对象的创建。

      

        3、适配器模式  

                (一)、定义

                        将一个类的接口转换成客户端期望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作,主要解决接口不兼容的问题。

                (二)、结构

  简单来说就是Api A 通过适配器类的处理,转换为了Api B。比如现在有个手机充电头的需求,手机充电头只能接受15V的电压,而家庭电压是220V,我们采用适配器模式将220V的电压转变为15V的电压。

                (三)、代码实现
/**
 * @Description: 家庭电压 api
 */
public interface HouseVoltage {

    /**
     * @description: 输出家庭电压
     *
     * @return: int
     **/
    public int outputVoltage();
}

public class HouseVoltageImpl implements HouseVoltage {

    @Override
    public int outputVoltage() {
        return 220;
    }
}

/**
 * @Description: 手机电压 api
 */
public interface PhoneVoltage {

    /**
     * @description: 输出手机电压
     *
     * @return: int
     **/
    public int outputVoltage();
}


/**
 * @Description: 适配器
 */
public class Adapter implements PhoneVoltage {

    private HouseVoltage houseVoltage;

    public Adapter(HouseVoltage houseVoltage) {
        this.houseVoltage = houseVoltage;
    }

    /**
     * @description: 转变家庭电压成手机电压
     *
     * @return: int
     **/
    @Override
    public int outputVoltage() {
        int outputVoltage = this.houseVoltage.outputVoltage();
        // .............

        return 5;
    }
}

        4、模板方法模式

                (一)、定义

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

                (二)、结构

简单来说,我们可以定义一个骨架主类,将整个过程抽象划分成多个步骤。子类里可以按照抽象的步骤,完成各自不同的实现。既没有干扰的骨架的步骤,又分离开了多个类似流程不同的实现。

                (三)、代码实现
/**
 * @Description: 模板模式
 *      将每天的生活划分成几个步骤,定义出一个骨架
 */
public abstract class TemplateLife {

    /**
     * @description: 我常规的一天生活
     */
    protected void myOneDayLife() {
        this.getUp();
        this.dine();
        this.work();
        this.sleep();
    }

    /**
     * @description: 起床
     */
    public abstract void getUp();


    /**
     * @description: 吃饭
     */
    public abstract void dine();


    /**
     * @description: 工作
     */
    public abstract void work();

    /**
     * @description: 睡觉
     */
    public abstract void sleep();
}


/**
 * @Description: 工作日的一天生活
 */
public class WorkingDayLife extends TemplateLife {

    @Override
    public void getUp() {
        System.out.println("早起....");
    }

    @Override
    public void dine() {
        System.out.println("吃工作餐.....");
    }

    @Override
    public void work() {
        System.out.println("工作挣钱......");
    }

    @Override
    public void sleep() {
        System.out.println("加班很晚回家睡觉......");
    }
}


/**
 * @Description: 周末的一天生活
 */
public class WeekendLife extends TemplateLife {
    @Override
    public void getUp() {
        System.out.println("周末补觉........");
    }

    @Override
    public void dine() {
        System.out.println("在家里一起吃饭.......");
    }

    @Override
    public void work() {
        System.out.println("适当运动学习.....");
    }

    @Override
    public void sleep() {
        System.out.println("按时睡觉.........");
    }
}

/**
 * @Description: 模板模式的单元测试
 */
public class TemplateLifeTest {

    @Test
    public void test(){
        // 工作日的一天
        TemplateLife workingDayLife = new WorkingDayLife();
        workingDayLife.myOneDayLife();

        System.out.println("======================================");

        // 周末的一天
        TemplateLife weekendLife = new WeekendLife();
        weekendLife.myOneDayLife();
        
    }
}

好了,今天就分享到这里,下一篇咱们接着再做笔记~

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值