设计模式

设计模型

设计模式分类
  1. 创建型模式:单例模式、抽象工厂模式、工厂模式、原型模式、建造者模式
  2. 结构型模式:组合模式、装饰者模式、外观模式、代理模式、桥接模式、适配器模式、享元模式
  3. 行为型模式:模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式(责任链)

单例设计模式

介绍:

采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只是提供一个取得其对象实例的方法。

注意事项和细节说明
  • 单例保证系统中只存在一个对象,节省了系统资源对于需要频繁创建销毁的对象,使用单例可以提高系统性能
  • 实例化单例类的时候,使用类的获取方法而不是new
  • 使用情景:频繁创建和销毁的对象、创建对象时耗时过多或耗费资源过多(重量级对象),但是经常需要用到的对象、工具类。例入频繁访问数据库或者文件的对象(比如数据源、session工厂)。
常见的单例实现方式
  1. 饿汉式(静态常量)
  2. 饿汉式(静态代码块)
  3. 懒汉式(线程不安全)
  4. 懒汉式(线程安全synchornized方法锁)
  5. 懒汉式(线程同步代码块不安全)
  6. 懒汉式(代码安全双重检查)
  7. 静态内部类
  8. 枚举
1、饿汉式(静态常量)

优缺点分析

优点:写法简单,随着类的装载完成实例化。避免线程同步问题。

缺点:在类装载的时候完成,当类不使用的时候会造成浪费。

结论:方法可用但是会造浪费

步骤

1、构造方法私有化
2、静态常量类成员
3、定义静态返回类对象方法

代码实现

public class type1 {
    public static void main(String[] args) {
        System.out.println("---------start-------------");
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2);
        System.out.println("---------end ------------");
    }

}

//饿汉式
class Singleton {
    //私有化构造方法
    private Singleton() {
    }
    //创建对象
    private final static Singleton instance = new Singleton();
    //创建对象获取方法
    public static Singleton getInstance() {
        return instance;
    }
}
2、饿汉式(静态代码块)

优缺点分析

缺点:静态代码块比较静态常量在类的加载时候就被实现,不使用会造成浪费。

优点:代码简单

代码实现

public class type2 {
    public static void main(String[] args) {
        System.out.println("---------start-------------");
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2);
        System.out.println("---------end----------------");
    }
}

//饿汉式
class Singleton2 {
    //私有化构造方法
    private Singleton2() {
    }

    private  static Singleton2 instance;

    static {
        instance = new Singleton2();
    }

    //创建对象
    //创建对象获取方法
    public static Singleton2 getInstance() {
        return instance;
    }
}
3、懒汉式(线程不安全)

优缺点:

优点:在类不使用的时候不创建

缺点:致命。在多线程下不安全

实现步骤

1、私有化构造方法。
2、定义类对象成员变量
3、定义一个方法获取类在判断类成员变量为空时创建(new)该类,赋予成员变量

代码实现

public class type3 {
    public static void main(String[] args) {
        System.out.println("---------懒汉式start-------------");
        Singletom instance1 = Singletom.getInstance();
        Singletom instance2 = Singletom.getInstance();
        System.out.println(instance1 == instance2);
        System.out.println("---------懒汉式end----------------");
    }
}

class Singletom {

    //私有化构造方法
    private Singletom() {
    }
    //定义对象
    private static Singletom singleton;
    //同步机制放在方法层面
    public static Singletom getInstance() {
        if (singleton == null) {
            new Singletom();
        }
        return singleton;
    }
}
4、懒汉式(线程安全)

优缺点

优点:线程安全、可用

缺点:性能问题

代码步骤

与线程不安全的区别在于给类获取方法添加synchornized线程锁

代码实现

public class type3 {
    public static void main(String[] args) {
        System.out.println("---------懒汉式start-------------");
        Singletom instance1 = Singletom.getInstance();
        Singletom instance2 = Singletom.getInstance();
        System.out.println(instance1 == instance2);
        System.out.println("---------懒汉式end----------------");
    }
}

class Singletom {

    //私有化构造方法
    private Singletom() {
    }

    //定义对象
    private static Singletom singleton;

    //synchornized线程安全模式但是有性能
    //同步机制放在方法层面
    public static synchronized Singletom getInstance() {
        if (singleton == null) {
           new Singletom();
        }
        return singleton;
    }
}
5、懒汉式(同步代码块)

优缺点

优点:性能高

缺点:不安全

代码步骤

与线程不安全的区别在于给方法内部添加synchornized线程同步锁

代码实现

public class type3 {
    public static void main(String[] args) {
        System.out.println("---------懒汉式start-------------");
        Singletom instance1 = Singletom.getInstance();
        Singletom instance2 = Singletom.getInstance();
        System.out.println(instance1 == instance2);
        System.out.println("---------懒汉式end----------------");
    }
}

class Singletom {

    //私有化构造方法
    private Singletom() {
    }

    //定义对象
    private static Singletom singleton;

    //解决性能问题,同步代码块但是不安全
    public static Singletom getInstance() {

        if (singleton == null) {
            //两个线程同时卡在这
            synchronized (Singletom.class) {
                new Singletom();
            }
        }
        return singleton;
    }
}
6、懒汉式(双重检查)

优缺点

优点:安全、性能较高

缺点:慢

代码步骤

1、私有化构造方法
2、定义类成员变量
3、定义公有方法返回类对象
3.1、synchornized加锁
3.2、当类成员变量为空时
3.3、synchornized加锁

代码实现

public class type4 {
    public static void main(String[] args) {
        System.out.println("---------懒汉式线程安全且性能不受影响start-------------");
        Sington4 instance1 = Sington4.getSinton();
        Sington4 instance2 = Sington4.getSinton();
        System.out.println(instance1 == instance2);
        System.out.println("---------懒汉式线程安全且性能不受影响end----------------");
    }
}
/**
 * 线程安全且性能较高
 */
class Sington4 {
    private Sington4() {
    }

    private static volatile Sington4 sinton;

    public static Sington4 getSinton() {
        if (sinton == null) {
            synchronized (Sington4.class) {
                if (sinton == null) {
                    new Sington4();
                }
            }
        }
        return sinton;
    }
}
7、静态内部类

优缺点

优点:安全、性能较高

缺点:暂无

代码步骤

1、私有化构造方法
2、定义类成员变量
3、内部静态方法利用类加载机制对成员变量赋值
4、定义方法获取类成员对象

代码实现

public class type5 {
    public static void main(String[] args) {
        System.out.println("-利用静态内部类对类加载的安全性,对类对象进行创建start-");
        Singleton6 instance1 = Singleton6.getInstance();
        Singleton6 instance2 = Singleton6.getInstance();
        System.out.println(instance1 == instance2);
        Runtime rn=Runtime.getRuntime();
        System.out.println("------------end----------------");

    }
}

class Singleton6 {
    private Singleton6() {
    }
	//懒加载线程安全
    private static class Singleton7 {
        private static final Singleton6 SINGLETON_6 = new Singleton6();
    }

    public static Singleton6 getInstance() {
        return Singleton7.SINGLETON_6;
    }
}
8、枚举方法

优缺点

优点:代码简单且安全、防止反序列化

缺点:

实现步骤

1、定义枚举对象(利用枚举的类加载机制)

代码实现

public class type5 {
    public static void main(String[] args) {
        System.out.println("------------start--------------");
        Singleton instance1 = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance1 == instance2);
        Runtime rn=Runtime.getRuntime();
        System.out.println("------------end----------------");

    }
}
enum Singleton{
	INSTANCE;
}

工厂模式

介绍:
  1. 工厂模式的意义

将实例化对象的代码提取出来,放在一个类中统一管理和维护,达到和主项目的依赖关系的解耦。

  1. 三种工厂模式
    • 简单工厂模式
    • 工厂方法模式
    • 抽象工厂模式
  2. 设计模式的依赖抽象原则
    • 创建对象时不要直接new对象,而是把这个new类的动作放到一个工厂的方法中并返回。也叫做不要直接持有具体类的引用。
    • 不要让类继承具体类,而是继承抽象类或者实现接口
    • 不要覆盖基类中已经实现的方法。
传统工厂模式

优缺点分析

优点:比较好理解,容易操作。

缺点:违反了设计模式OPC原则(对修改关闭对扩展开放)。

代码思路

对披萨进行抽象利用多态做到对具体对象的选择

代码实现

/**
 * 抽象披萨接口
 */
public interface Pizza {
    /**
     * 选材
     */
    void prepare();

    /**
     * 烘焙
     */
    void bake();

    /**
     * 切割
     */
    void cut();

    /**
     * 打包
     */
    void box();
}
public class CheessPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备芝士披萨");
    }

    @Override
    public void bake() {
        System.out.println("烘焙芝士披萨");
    }

    @Override
    public void cut() {
        System.out.println("切割芝士披萨");
    }

    @Override
    public void box() {
        System.out.println("打包芝士披萨");
    }
}
public class GreekPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("希腊披萨准备");
    }

    @Override
    public void bake() {
        System.out.println("希腊披萨烘焙");
    }

    @Override
    public void cut() {
        System.out.println("希腊披萨切割");
    }

    @Override
    public void box() {
        System.out.println("希腊披萨打包");
    }
}
public class ChinaPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("中国披萨准备");
    }

    @Override
    public void bake() {
        System.out.println("中国披萨烘焙");
    }

    @Override
    public void cut() {
        System.out.println("中国披萨切割");
    }

    @Override
    public void box() {
        System.out.println("中国披萨打包");
    }
}
public class OrderPizza {
    //希腊披萨
    private static final String GREKPIZZA = "Greek";
    //芝士披萨
    private static final String CHEESSPIZZA = "Cheess";
    //中国披萨
    private static final String CHINAPIZZA = "China";

    /**
     * 订购披萨
     */
    public OrderPizza() {
        do {
            Pizza pizza = null;
            String pizzaType = getType();
            pizza = getPizza(pizzaType);
            if (pizza != null) {
                pizza.prepare();
                pizza.box();
                continue;
            } else {
                continue;
            }
        } while (true);
    }

    /**
     * 根据pizza类型返回不同的披萨
     *
     * @param pizzaType
     * @return
     */
    private Pizza getPizza(String pizzaType) {
        //披萨对象
        Pizza pizza=null;
        if (GREKPIZZA.equals(pizzaType)) {
            pizza = new GreekPizza();
        }
        if (CHEESSPIZZA.equals(pizzaType)) {
            pizza = new CheessPizza();
        }
        if (CHINAPIZZA.equals(pizzaType)) {
            pizza = new ChinaPizza();
        }
        return pizza;
    }

    /**
     * 获取控制台输入
     *
     * @return
     */
    private String getType() {
        System.out.println("请输入需要订购的披萨种类:");
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        return str;
    }
}
 /**
    * 测试
    *
    */
public class PizzaStore {
    public static void main(String[] args) {
        OrderPizza op = new OrderPizza();
    }
}
简单工厂

简介

对传统工厂的一个升级。再增加类的类型的时候涉及到对选择模块方法的修改。我们对选择判断模块类进行抽取隔离为一个单独的工厂就是简单工厂。

  • 简单工厂模式属于创建型模式,是工程模式的一种。简单工厂模式就是由一个简单工厂对象决定创建那个产品的实例。
  • 简单工厂模式:定义一个创建对象的类,有这个类来封装实例化对象的行为。
  • 在软件产开发中,我们会用到大量的创建某种、某类或者某批对象时候,就会用到工厂模式。
/**
 * 抽象披萨接口
 */
public interface Pizza {
    /**
     * 选材
     */
    void prepare();

    /**
     * 烘焙
     */
    void bake();

    /**
     * 切割
     */
    void cut();

    /**
     * 打包
     */
    void box();
}
public class CheessPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备芝士披萨");
    }

    @Override
    public void bake() {
        System.out.println("烘焙芝士披萨");
    }

    @Override
    public void cut() {
        System.out.println("切割芝士披萨");
    }

    @Override
    public void box() {
        System.out.println("打包芝士披萨");
    }
}
public class GreekPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("希腊披萨准备");
    }

    @Override
    public void bake() {
        System.out.println("希腊披萨烘焙");
    }

    @Override
    public void cut() {
        System.out.println("希腊披萨切割");
    }

    @Override
    public void box() {
        System.out.println("希腊披萨打包");
    }
}

public class ChinaPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("中国披萨准备");
    }

    @Override
    public void bake() {
        System.out.println("中国披萨烘焙");
    }

    @Override
    public void cut() {
        System.out.println("中国披萨切割");
    }

    @Override
    public void box() {
        System.out.println("中国披萨打包");
    }
}
public class OrderPizza {
   /**
     * 订购披萨
     */
    public OrderPizza(SimpleFactory simpleFactory) {
        do {
            Pizza pizza = null;
            String pizzaType = getType();
            pizza = simpleFactory.getPizza(pizzaType);
            if (pizza != null) {
                pizza.prepare();
                pizza.box();
                continue;
            } else {
                continue;
            }
        } while (true);
    }

    /**
     * 获取控制台输入
     *
     * @return
     */
    private String getType() {
        System.out.println("请输入需要订购的披萨种类:");
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        return str;
    }
}
public class SimpleFactory {
    //希腊披萨
    private static final String GREKPIZZA = "Greek";
    //芝士披萨
    private static final String CHEESSPIZZA = "Cheess";
    //中国披萨
    private static final String CHINAPIZZA = "China";

    /**
     * 根据pizza类型返回不同的披萨
     *
     * @param pizzaType
     * @return
     */
    public Pizza getPizza(String pizzaType) {
        System.out.println("-----使用简单工厂模式创建对象-------");
        //披萨对象
        Pizza pizza = null;
        if (GREKPIZZA.equals(pizzaType)) {
            pizza = new GreekPizza();
        }
        if (CHEESSPIZZA.equals(pizzaType)) {
            pizza = new CheessPizza();
        }
        if (CHINAPIZZA.equals(pizzaType)) {
            pizza = new ChinaPizza();
        }
        return pizza;
    }

}
public class PizzaStore {
    public static void main(String[] args) {
        //创建工厂对象
        SimpleFactory simpleFactory = new SimpleFactory();
        OrderPizza op = new OrderPizza(simpleFactory);
    }
}
工厂方法模式

简介

  • 工厂方法模式设计方案:将项目的实例化功能抽象成抽象方法
  • 工厂方法模式:定义一个创建对象的抽象对象,由子类决定要实例化的对象。工厂方法模式将对象的实例化推迟到子类。

优缺点分分析

实现思路

1、抽象出类A
2、具体的类继承抽象类,a1,a2,a3
3、创建一个抽象工厂Factorty类并创建一个方法method(返回值是A)。
4、定义具体的工厂实现该抽象工厂并重写方法。
5、使用者调用具体的抽象工厂创建对象
public abstract class Pizza {

    /**
     * 抽象方法准备
     */
    protected abstract void prepare();

    /**
     * 抽象方法烘焙
     */
    protected abstract void bake();

    /**
     * 抽象方法切割
     */
    protected abstract void cut();

    /**
     * 抽象方法打包
     */
    protected abstract void box();
}
public class BeiJingCheessPizza extends Pizza {
    /**
     * 北京芝士披萨名称
     */
    private String name;

    @Override
    protected void prepare() {
        System.out.println(name + "北京芝士披萨准备");
    }

    @Override
    protected void bake() {

    }

    @Override
    protected void cut() {

    }

    @Override
    protected void box() {

    }
}
public abstract class PizzaOrder {
    /**
     * 创建披萨抽象方法
     *
     * @param type
     * @return
     */
    abstract Pizza createPizza(String type);

    /**
     * 订购披萨
     */
    public PizzaOrder() {
        do {
            String pizzaType = getType();
            Pizza pizza = createPizza(pizzaType);
            if (pizza != null) {
                pizza.prepare();
                pizza.box();
                continue;
            } else {
                continue;
            }
        } while (true);
    }

    /**
     * 获取控制台输入
     *
     * @return
     */
    private String getType() {
        System.out.println("请输入需要订购的披萨种类:");
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        return str;
    }
}
public class BeiJingOrder extends PizzaOrder {
    private static final String BEIJINGCHEESS = "BJCheess";

    @Override
    Pizza createPizza(String type) {
        Pizza pizza=null;
        if (BEIJINGCHEESS.equals(type)) {
            pizza=new BeiJingCheessPizza();
        }
        return pizza;
    }
}

public class PizzaStore {
    public static void main(String[] args) {
        BeiJingOrder beiJingOrder = new BeiJingOrder();
        beiJingOrder.createPizza("dea");
    }
}

抽象工厂模式

介绍

抽象工厂模式:定义一个interface用于创建完成所有依赖关系的对象簇,而无需指明具体的类。抽象工厂模式可以将简单工厂模式和方法模式进行整合。

设计层面来说,抽象工厂就是对简单工厂的进一步抽象(工厂层面),做到类的对象可选择、创建类的工厂可选择。

将工厂抽象成两层,抽象工厂涉及的工厂子类。程序员可以动态选择创建对象的工厂,这样工厂就变成了工厂簇,利于代码的维护和扩展。

代码步骤

1、抽象出要创建的对象。
2、创建具体对象。
3、创建抽象工厂用与创建对象(返回对象类型)。
4、创建具体的工厂用来创建不同类的对象(返回具体的类)。
5、定义一个共公类,对抽象工厂进行动态选择创建对象的工厂,并调用具体的工厂实现类方法的创建。

代码实现


public abstract class Pizza {
    protected String name;

    /**
     * 选材
     */
    void prepare(){
        System.out.println(name+"选择材料");
    };

    /**
     * 烘焙
     */
    void bake(){
        System.out.println(name+"选择烘焙");
    };

    /**
     * 切割
     */
    void cut(){
        System.out.println(name+"选择切割");
    };

    /**
     * 打包
     */
    void box(){
        System.out.println(name+"选择打包");
    };

    public void setName(String name) {
        this.name = name;
    }
}
public class CheessPizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京芝士披萨");
    }

    @Override
    public void bake() {
    }

    @Override
    public void cut() {

    }

    @Override
    public void box() {

    }
}

public interface AbstactFactory {
    /**
     * 创建Pizza对象
     * @return
     */
    Pizza createPizza(String typePizza);
}
public class BeiJingPizzaFactory implements AbstactFactory {
    @Override
    public Pizza createPizza(String typePizza) {
        Pizza pizza = null;
        if("BJCheess".equals(typePizza)){
            pizza=new CheessPizza();
        }
        return pizza;
    }
}
public class OrderPizza {
    AbstactFactory abstactFactory;
    /**
     * 订购披萨
     */
    public OrderPizza(AbstactFactory abstactFactory) {
        this.abstactFactory=abstactFactory;
        Pizza pizza = null;
        String pizzaType = getType();
        do {
            //工厂类在这灵活传送
            pizza = abstactFactory.createPizza(pizzaType);
            if (pizza != null) {
                pizza.prepare();
                pizza.box();
                continue;
            } else {
                continue;
            }
        } while (true);
    }

    /**
     * 获取控制台输入
     *
     * @return
     */
    private String getType() {
        System.out.println("请输入需要订购的披萨种类:");
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        return str;
    }
}

public class PizzaStore {
    public static void main(String[] args) {
        BeiJingPizzaFactory bjFactory = new BeiJingPizzaFactory();
        new OrderPizza(bjFactory);
    }
}

原型模式

实现方式
  1. 传统方法:复制对象(通过构造方法利用get、set方法获取对象)
    • 优缺点分析,需要获取元素属性、如果创建对象比较复杂字段较多则效率低下。
    • 重新优化初始化对象、而不是动态的获取对象运行时候的状态不够灵活。
  2. 原型模式:利用Object的根类中clone进行对象复制。
    • 创建对象类需要实现Cloneable接口,该接口表示该类能够复制且具有复制的能力。
  3. 浅拷贝的介绍
    • 对于数据类型是基本类型的成员变量,在进行对象拷贝的时候直接进行对象值传递,也就是将改属性值复制一份给新的对象。
    • 对与数据类型是引用型的成员变量(数组、对象),在进行对象拷贝的时候都是简单的进行对象的引用传递,也就是只是将对象的引用地址复制一份给新的对象。
    • 导致的问题,对象引用相同,在其他对象修改引用对象会对其他对象造成影响。
  4. 深拷贝的介绍
    • 复制对象的所有基本数据类型的成员变量
    • 对所有引用数据类型的成员变量申请存储空间,并复制每个引用对象数据类型成员变量所应用的对象, 直到该对象可达的所有对象。
    • 使用java对象序列化进行拷贝推荐使用
原型注意事项和细节
  1. 创建对象比较复杂可以利用原型模式简化创建对象的过程。
  2. 不用初始化对象而是动态的获取对象运行状态。对象增加或者减少属性都兼容
  3. 在实现深克隆的时候可能需要比较复杂的代码。
  4. 缺点:所有以来的类都需要实行cloneable接口。
	public class Base implements Serializable, Cloneable {
    private int id;
    private String name;
    private double salary;
    private Wife wife;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public Wife getWife() {
        return wife;
    }

    public void setWife(Wife wife) {
        this.wife = wife;
    }

    public Base() {

    }

    public Base(int id, String name, double salary, Wife wife) {
        this.id = id;
        this.name = name;
        this.salary = salary;
        this.wife = wife;
    }

    //返回对象 缺点是必须所有的对象都实现cloneable接口
    @Override
    public Base clone() throws CloneNotSupportedException {
        Object base;
        base = super.clone();
        Base baseDeep = (Base) base;
        baseDeep.wife = (Wife) wife.clone();
        return baseDeep;
    }

    public Object baseClone() {
        Object o = null;
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bio = null;
        ObjectInputStream os = null;
        try {
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            //利用序列化对象把所有的元素都序列化
            oos.writeObject(this);
            //反序列化
            bio=new ByteArrayInputStream(bos.toByteArray());
            os=new ObjectInputStream(bio);
            o = os.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                os.close();
                bio.close();
                oos.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return o;
    }

    @Override
    public String toString() {
        return "Base{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                ", wife=" + wife +
                '}';
    }
}


public class Wife implements Cloneable, Serializable {
    private int id;

    public int getId() {
        return id;
    }

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

    @Override
    public Wife clone() throws CloneNotSupportedException {
        return (Wife) super.clone();
    }

    @Override
    public String toString() {
        return "Wife{" +
                "id=" + id +
                '}';
    }
}

public class test {
    public static void main(String[] args) {
        Base base = new Base();
        base.setId(11);
        base.setName("阿玉");
        base.setSalary(212.1);
        Wife wife = new Wife();
        wife.setId(22);
        base.setWife(wife);
        System.out.println("---" + base.toString() + base.getWife().hashCode());
        Base baseClone = null;
        try {
            //引用类也clone
            //baseClone = base.clone();
            baseClone = (Base) base.baseClone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("---" + baseClone.toString() + baseClone.getWife().hashCode());

    }
}

建造者模式

分析

生产不同的产品,通过生产步骤或者生产的条件达到对产品的控制。

传统实现方式

实现方式

通过抽象对象的实现方式,定义抽象接口。然后由具体的实现类对类进行实现,通过对具体实现类的创造达到对不同产品的实现。利用多态。

优缺点分析

  1. 优点是好理解,简单操作。
  2. 缺点:设计过程单一,程序的拓展和可维护性不高,产品的创建过程和产品紧密结合在一起。
建造者模式
  1. product(产品角色):一个具体的产品。
  2. Builder(建造者):创建一个product的各个部分的接口/抽象类。
  3. ConcreteBuilder(具体的建造者):实现接口,构建和装配各个部件。
  4. Director(指挥者):构建一个使用builder接口的对象。它主要是用于创建一个复杂的对象。
    • 隔离了客户与对象的生产过程。
    • 负责控制产品的生产过程。
建造者模式注意事项和细节
  1. 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程进行解耦,使得使用相同的创建过程可以创建不同的产品对象。

  2. 每一个具体的建造者相互独立,而与其他产品的建造者无关,因此可以很方便的替换具体建造者或增加新的具体的建造者,用户在使用的时候只是用不同的具体建造者就可以得到不同的个产品对象。符合开闭原则。

  3. 可以更加精细的控制产品的创建过程,将复杂的产品创建步骤分解在不同的方法中,使得创建过程更加清晰,也更加方便实用程序来控制创建过程。

  4. 建造者模式创建的产品具有很多共性,组成部分很相似,如果产品的差异较大不适合用建造者模式。

  5. 抽象工厂和建造者模式的区分

    • ​ 总结来说,抽象工厂关心的创建一系列产品、建造者则是具体的产品构建细节

    • 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品,具有不同分类维度的产品组合。采用抽象工厂模式,不需要关心产品的具体过程,只关心产品是由那个工厂产生的。

    • 建造者则是对产品的详细步骤进行把控。或者说是按照指定多个蓝图建造产品,主要的目的是通过组装零件而产生的一个产品。

代码

public class House {
    /**
     * 打地基
     */
    private String buildBasice;

    /**
     * 盖顶
     */
    private String buildTop;

    public String getBuildBasice() {
        return buildBasice;
    }

    public void setBuildBasice(String buildBasice) {
        this.buildBasice = buildBasice;
    }

    public String getBuildTop() {
        return buildTop;
    }

    public void setBuildTop(String buildTop) {
        this.buildTop = buildTop;
    }
}



public abstract class HouseBuilder {

    protected House house = new House();

    /**
     * 定义创建对象的抽象方法
     */
    public abstract void buildBaisc();

    /**
     * 定义创建对象的抽象方法
     */
    public abstract void buildTop();

    /**
     * 定义一个返回房子的对象
     * @return
     */
    public House build() {
        return house;
    }
}

public class CommonBuild extends HouseBuilder {
    @Override
    public void buildBaisc() {
        System.out.println("普通住宅地基五米");
    }

    /**
     * 定义创建对象的抽象方法
     */
    @Override
    public void buildTop() {
        System.out.println("普通房子吊顶");
    }
}



public class BuildDirector {

    HouseBuilder houseBuilder = null;
	//两种方式来传递参数
    //方式1、通过构造方法
    public BuildDirector(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }
	//方式2、通过set属性方法
    public void setBh(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    //指挥者造房子
    public House constructHouse() {
        houseBuilder.buildBaisc();
        houseBuilder.buildTop();
        return houseBuilder.build();
    }
}


public class BuildHouser {
    public static void main(String[] args) {
        CommonBuild commonBuild = new CommonBuild();
        BuildDirector bd = new BuildDirector(commonBuild);
        House house = bd.constructHouse();
    }

}

适配器

介绍
  1. 适配器模式将某个类的接口转化成客户端期望的某种表示。主要的目的是兼容性。让原本因接口不匹配的两个类可以转化适用。
  2. 适配器模式属于结构性模式
  3. 分为三类
    • 类适配器模式
    • 对象适配器模式
    • 接口适配器模式
工作原理
  1. 适配器模式:将一个类的接口转化为另一种接口。不兼容到兼容
  2. 用户角度是看不到适配器的,所以说是解耦。
  3. 用户调用适配器转化出来的目标接口方法,适配器在调用被适配者相关接口方法。
posted @ 2021-03-26 14:20  墨水梦想  阅读(94)  评论(0)    收藏  举报