设计模式一——创建型模式(笔记)

    技术2022-07-11  132

    简要描述

    这些设计模式提供了一种方式:在创建对象的时候隐藏创建逻辑。(不是使用new运算符直接实例化对象)

    带来的效果:使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

    包括:工厂模式,抽象工厂模式,单例模式,建造者模式,原型模式。

    设计模式的六大原则: 1、开闭原则:对扩展开发,对修改关闭。用到了接口和抽象类。 2、里氏代换原则:对实现抽象化(基类和子类的继承关系)的具体步骤的规范。 3、依赖倒转原则:针对接口编程,依赖于抽象而非具体。是开闭原则的基础。 4、接口隔离原则:使用多个隔离的接口,降低类间耦合度。 5、迪米特法则(最少知道原则):一个实体尽量少地和其他实体发生相互作用,使得系统功能模块相对独立。 6、合成复用原则:尽量使用合成/聚合,而不是使用继承。

    一、工厂模式

    介绍: 定义一个创建对象的接口,子类实现工厂接口(自己决定实例化哪一个工厂类)。

    优点: 1、调用者创建对象时,只需要知道其名称; 2、扩展性高,增加一个产品只需要扩展一个工厂类; 3、屏蔽了具体实现,调用者只关心接口。

    缺点:增加一个产品时,需要加一个具体类和对象实现工厂,使得类的个数成倍增加,从而增加了系统复杂度和系统具体类的依赖。 注:适用于复杂对象的生成。

    使用时机:明确地计划不同条件下创建不同实例时。

    实现: 以创建形状为例 步骤1:创建接口shape.java

    public interface Shape { /** * 创建了一个接口 */ void draw(); }

    步骤2:创建实现接口的实体类RecTangle.java,Square.java,Circle.java

    public class RecTangle implements Shape { /** * 创建接口的实现类Rectangle */ @Override public void draw() { // TODO 自动生成的方法存根 System.out.println("Rectangle"); } } public class Circle implements Shape { /** * 创建接口的实现类Circle */ @Override public void draw() { // TODO 自动生成的方法存根 System.out.println("Circle"); } } public class Square implements Shape { /** * 创建接口的实现类Square */ @Override public void draw() { // TODO 自动生成的方法存根 System.out.println("Square"); } }

    步骤3:创建工厂ShapeFactory.java

    public class ShapeFactory { /** * 创建工厂,生成实体类的对象 * @param shapeType * @return */ public Shape getShape(String shapeType) { if(shapeType==null) { return null; } if(shapeType.equals("R")) { return new RecTangle(); } if(shapeType.equals("S")) { return new Square(); } if(shapeType.equals("C")) { return new Circle(); } return null; } }

    步骤4:使用工厂(通过传递类型信息获取实体类对象)

    public class FactoryTest { /** * 测试 * 工厂类产生工厂对象 * 工厂对象调用工厂内方法来获取实体类对象 * @param args */ public static void main(String[] args) { ShapeFactory shapeFactory=new ShapeFactory(); Shape s1=shapeFactory.getShape("C"); s1.draw(); Shape s2=shapeFactory.getShape("R"); s2.draw(); Shape s3=shapeFactory.getShape("S"); s3.draw(); } }

    二、抽象工厂模式

    围绕一个超级工厂(其他工厂的工厂)创建其他工厂。

    介绍: 抽象工厂包含许多具体工厂,每一个具体工厂里面有多种具体产品。

    缺点:产品族扩展非常困难,要增加某个系列的某一产品,既要在抽象的Creator里面加代码,又要在具体的里面加代码。

    使用时机:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

    实现:

    步骤1:为形状创建一个接口

    package implement; public interface Shape { /** * 创建了一个接口 */ void draw(); }

    步骤2:创建接口的实现类

    package implementclass; import implement.Shape; public class RecTangle implements Shape { /** * 创建接口的实现类Rectangle */ @Override public void draw() { // TODO 自动生成的方法存根 System.out.println("Rectangle"); } } package implementclass; import implement.Shape; public class Square implements Shape { /** * 创建接口的实现类Square */ @Override public void draw() { // TODO 自动生成的方法存根 System.out.println("Square"); } } package implementclass; import implement.Shape; public class Circle implements Shape { /** * 创建接口的实现类Circle */ @Override public void draw() { // TODO 自动生成的方法存根 System.out.println("Circle"); } }

    步骤3:为颜色创建一个接口

    package implement; public interface Color { void fill(); }

    步骤4:创建接口的实现类

    package implementclass; import implement.Color; public class Red implements Color { @Override public void fill() { // TODO 自动生成的方法存根 System.out.println("红"); } } package implementclass; import implement.Color; public class Green implements Color { @Override public void fill() { // TODO 自动生成的方法存根 System.out.println("绿"); } } package implementclass; import implement.Color; public class Blue implements Color{ @Override public void fill() { // TODO 自动生成的方法存根 System.out.println("蓝"); } }

    步骤5:为形状和颜色对象创建抽象类来获取工厂

    package abstractfactory; import implement.Color; import implement.Shape; public abstract class AbstractFactory { public abstract Color getColor(String color); public abstract Shape getShape(String shape); }

    步骤6:创建抽象类的工厂类

    package factoryji; import abstractfactory.AbstractFactory; import implement.Color; import implement.Shape; import implementclass.Blue; import implementclass.Green; import implementclass.Red; public class ColorFactory extends AbstractFactory{ @Override public Color getColor(String color) { // TODO 自动生成的方法存根 if(color==null) { return null; } if(color.equalsIgnoreCase("h")) { return new Red(); } if(color.equalsIgnoreCase("g")) { return new Green(); } if(color.equalsIgnoreCase("b")) { return new Blue(); } return null; } @Override public Shape getShape(String shape) { // TODO 自动生成的方法存根 return null; } } package factoryji; import abstractfactory.AbstractFactory; import implement.Color; import implement.Shape; import implementclass.Circle; import implementclass.RecTangle; import implementclass.Square; public class ShapeFactory extends AbstractFactory { /** * 创建工厂,生成实体类的对象 * @param shapeType * @return */ public Shape getShape(String shapeType) { if(shapeType==null) { return null; } if(shapeType.equals("r")) { return new RecTangle(); } if(shapeType.equals("s")) { return new Square(); } if(shapeType.equals("c")) { return new Circle(); } return null; } @Override public Color getColor(String color) { // TODO 自动生成的方法存根 return null; } }

    步骤7:创建一个工厂生成器类

    package vvcreatefactory; import abstractfactory.AbstractFactory; import factoryji.ColorFactory; import factoryji.ShapeFactory; public class FactoryProducer { public static AbstractFactory getFactory(String choice) { if(choice.equalsIgnoreCase("shape")) { return new ShapeFactory(); } if(choice.equalsIgnoreCase("color")) { return new ColorFactory(); } return null; } }

    步骤8:测试使用

    package abstractfactorytest; import abstractfactory.AbstractFactory; import createfactory.FactoryProducer; import implement.Color; import implement.Shape; public class AbstractFactorytest { public static void main(String[] args) { AbstractFactory shapeFactory = FactoryProducer.getFactory("shape"); Shape shape1=shapeFactory.getShape("c"); Shape shape2=shapeFactory.getShape("r"); Shape shape3=shapeFactory.getShape("s"); shape1.draw(); shape2.draw(); shape3.draw(); AbstractFactory colorFactory=FactoryProducer.getFactory("color"); Color color1=colorFactory.getColor("h"); Color color2=colorFactory.getColor("b"); Color color3=colorFactory.getColor("g"); color1.fill(); color2.fill(); color3.fill(); } }

    三、单例模式

    单例类只能有一个实例 单例类必须自己创建自己的唯一实例 单例类必须给所有其他对象提供这一实例

    适用时机:控制实例数目,节省系统资源的时候。

    优点: 1、减少了内存开销(尤其是频繁的创建和销毁实例) 2、避免对资源的多重占用 缺点:没有接口,不能继承

    实现

    步骤1:创建一个类

    public class SingleObject { private static SingleObject instance=new SingleObject(); private SingleObject() { } public static SingleObject getInstance() { return instance; } public void showMessage() { System.out.println("single"); } }

    步骤2:获取唯一对象

    public class Singletest { public static void main() { SingleObject object=SingleObject.getInstance(); object.showMessage(); } }

    四、建造者模式

    使用多个简单的对象一步一步构建成一个复杂的对象。一个Builder类会一步步构造最终对象,该Builder类独立于其他对象。

    一个复杂对象由各个部分的子对象以一定算法构成,由于需求变化,复杂对象的各个部分经常发送剧烈变化,但组合在一起的算法相对稳定。

    eg:JAVA中的SpringBuilder

    优点: 1、易扩展 2、便于控制细节风险 缺点: 1、产品必须由共同点,范围有限 2、如内部变化复杂,会有很多的建造类

    使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

    与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

    实现: 快餐店案例 步骤1:创建食物条目和食物包装的接口

    package implement; public interface Item { public String name(); public Packing packing(); public float price(); } package implement; public interface Packing { public String pack(); }

    步骤2:创建实现包装接口的实体类

    package implementpacking; import implement.Packing; public class Bottle implements Packing{ @Override public String pack() { // TODO 自动生成的方法存根 return "瓶子"; } } package implementpacking; import implement.Packing; public class Wrapper implements Packing{ public String pack() { // TODO 自动生成的方法存根 return "纸袋子"; } }

    步骤3:创建实现食物条目接口的抽象类

    package implementsitemabstract; import implement.Item; import implement.Packing; import implementpacking.Wrapper; public abstract class Burger implements Item{ public Packing packing() { return new Wrapper(); } public abstract float price(); } package implementsitemabstract; import implement.Item; import implement.Packing; import implementpacking.Bottle; public abstract class ColdDrink implements Item{ public Packing packing() { return new Bottle(); } public abstract float price(); }

    步骤4:创建扩展抽象类的实体类

    package entityclass; import implementsitemabstract.Burger; public class BurgerChicken extends Burger { @Override public String name() { // TODO 自动生成的方法存根 return "鸡肉汉堡"; } @Override public float price() { // TODO 自动生成的方法存根 return 25.0f; } } package entityclass; import implementsitemabstract.Burger; public class BurgerVeg extends Burger{ @Override public String name() { // TODO 自动生成的方法存根 return "蔬菜汉堡"; } @Override public float price() { // TODO 自动生成的方法存根 return 15.0f; } } package entityclass; import implementsitemabstract.ColdDrink; public class Doujiang extends ColdDrink{ @Override public String name() { // TODO 自动生成的方法存根 return "豆浆"; } @Override public float price() { // TODO 自动生成的方法存根 return 9.0f; } } package entityclass; import implementsitemabstract.ColdDrink; public class Coke extends ColdDrink { @Override public String name() { // TODO 自动生成的方法存根 return "keke"; } @Override public float price() { // TODO 自动生成的方法存根 return 9.0f; } }

    步骤5:创建一个Meal类

    package meallist; import java.util.ArrayList; import java.util.List; import implement.Item; public class Meal { private List<Item> items=new ArrayList<>(); public void addItem(Item item) { items.add(item); } public float pay() { float all=0; for(Item item:items) { all+=item.price(); } return all; } public void show() { for(Item item:items) { System.out.println("清单:"+item.name()+",打包方式"+item.packing().pack()+",总金额"+item.price()); } } }

    步骤6:创建一个MealBuilder类,负责创建Meal

    package mealbuilder; import entityclass.BurgerChicken; import entityclass.BurgerVeg; import entityclass.Coke; import entityclass.Doujiang; import meallist.Meal; public class MealBuilder { //蔬菜汉堡+可口可乐 public Meal cookvac() { Meal meal=new Meal(); meal.addItem(new BurgerVeg()); meal.addItem(new Coke()); return meal; } //肉汉堡+豆浆 public Meal cookcad() { Meal meal=new Meal(); meal.addItem(new BurgerChicken()); meal.addItem(new Doujiang()); return meal; } }

    步骤7:test

    package test; import mealbuilder.MealBuilder; import meallist.Meal; public class BuildTest { public static void main(String[] args) { MealBuilder mealBuilder=new MealBuilder(); Meal m1=mealBuilder.cookcad(); m1.show(); System.out.println("总价:"+m1.pay()); Meal m2=mealBuilder.cookvac(); m2.show(); System.out.println("总价:"+m2.pay()); } }

    五、原型模式

    实现一个原型接口用于创建当前对象克隆。

    使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。

    注:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。

    实现: 步骤1:创建一个实现Cloneable接口的实现类

    package abstractimplement; public abstract class Shape implements Cloneable{ private String id; protected String type; protected abstract void draw(); public String getId() { return id; } public void setId(String id) { this.id = id; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Object clone() { Object clone=null; try { clone = super.clone(); }catch(CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }

    步骤2:创建扩展了上面抽象类的实体类。

    package entityclass; import abstractimplement.Shape; public class Circle extends Shape { public Circle() { type="圆"; } public void draw() { // TODO 自动生成的方法存根 System.out.println("圆"); } } package entityclass; import abstractimplement.Shape; public class Rectangel extends Shape{ public Rectangel() { type="三角"; } public void draw() { // TODO 自动生成的方法存根 System.out.println("三角"); } } package entityclass; import abstractimplement.Shape; public class Square extends Shape{ public Square() { type="方"; } public void draw() { // TODO 自动生成的方法存根 System.out.println("方"); } }

    步骤3:创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。

    package shapecache; import java.util.Hashtable; import abstractimplement.Shape; import entityclass.Circle; import entityclass.Rectangel; import entityclass.Square; public class ShapeCache { private static Hashtable<String,Shape> shapeMap=new Hashtable<String,Shape>(); public static Shape getShape(String shapeId) { Shape cachedShape = shapeMap.get(shapeId); return (Shape) cachedShape.clone(); } public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(),circle); Square square = new Square(); square.setId("2"); shapeMap.put(square.getId(),square); Rectangel rectangle = new Rectangel(); rectangle.setId("3"); shapeMap.put(rectangle.getId(),rectangle); } }

    步骤 4:使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    package test; import abstractimplement.Shape; import shapecache.ShapeCache; public class PrototypeTest { public static void main(String[] args) { ShapeCache.loadCache(); Shape clonedShape = (Shape) ShapeCache.getShape("1"); System.out.println("Shape : " + clonedShape.getType()); Shape clonedShape2 = (Shape) ShapeCache.getShape("2"); System.out.println("Shape : " + clonedShape2.getType()); Shape clonedShape3 = (Shape) ShapeCache.getShape("3"); System.out.println("Shape : " + clonedShape3.getType()); } }

    啊!再见!

    Processed: 0.017, SQL: 9