学习设计模式(一)

本文深入讲解了五种经典设计模式:单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式。通过实例代码详细解析了每种模式的原理与应用场景,帮助读者更好地理解和运用这些模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了方便巩固所学的设计模式,决定以边写总结边学习的方式加深理解。
设计模式就是众多的软件开发前人总结出来的代码设计经验,为了让代码重用性更高,更易于理解和扩展。
一、单例模式
首先从简单的开始,最先接触的是单例模式,属于创建型模式,它由自己创建自己的实例,并且只能有一个,所有其他对象获取到该类的实例都是同一个,保证该类的实例只被创建了一次。
比如一个人只有一个父亲,他的baby叫爸爸只有他一个,不会因为叫的次数多而改变,永远只有父亲这一个实例
代码示例:

public class SingleObject {
 
   //创建 SingleObject 的一个对象
   private static SingleObject instance = new SingleObject();
 
   //让构造函数为 private,这样该类就不会被实例化
   private SingleObject(){}
 
   //获取唯一可用的对象
   public static SingleObject getInstance(){
      return instance;
   }
 
   public void showMessage(){
      System.out.println("Hello World!");
   }
}
public class SingletonPatternDemo {
   public static void main(String[] args) {
 
      //不合法的构造函数
      //编译时错误:构造函数 SingleObject() 是不可见的
      //SingleObject object = new SingleObject();
 
      //获取唯一可用的对象
      SingleObject object = SingleObject.getInstance();
 
      //显示消息
      object.showMessage();
   }
}

二、工厂模式
工厂模式就是将类的实例化延迟到子类中,按需求实例化。
比如现在有一个汉堡店,店里有鸡腿汉堡、牛肉堡等,去店里报个名字别人就知道要做哪种汉堡。只将这一个汉堡类实例化而不实例化所有汉堡类。这就是工厂模式的原理,缺点就是一个工厂只能有一个种类的商品。汉堡店就只有汉堡,如果要增加冷饮等其他的只能再新建一个冷饮店(工厂类)。
代码示例:

public interface Shape {
   void draw();
}
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class ShapeFactory {
    
   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      }
      return null;
   }
}
public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();

      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //调用 Rectangle 的 draw 方法
      shape2.draw();
 
      //获取 Square 的对象,并调用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //调用 Square 的 draw 方法
      shape3.draw();
   }
}

三、抽象工厂模式
工厂模式略显单调,只是单一生产某一种商品,抽象工厂模式就稍微延申的一点点,为多种商品提供工厂。上面的工厂模式可以看到,几个类实现一个接口,想用哪个就实例化哪一个,抽象工厂模式就稍有不同,它在实现接口的类后工厂类前添加了一个抽象类,由这个抽象类控制工厂类生产哪些商品,这样就能使代码的扩展性变高。如果现在汉堡店里不只卖汉堡,还想卖冷饮、披萨,只需增加一个接口,再让抽象类实现这个新的接口对应的方法。
代码示例:

public interface Shape {
   void draw();
}
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}
public interface Color {
   void fill();
}
public class Red implements Color {
 
   @Override
   public void fill() {
      System.out.println("Inside Red::fill() method.");
   }
}
public class Green implements Color {
 
   @Override
   public void fill() {
      System.out.println("Inside Green::fill() method.");
   }
}
public class Blue implements Color {
 
   @Override
   public void fill() {
      System.out.println("Inside Blue::fill() method.");
   }
}
public abstract class AbstractFactory {
   public abstract Color getColor(String color);
   public abstract Shape getShape(String shape) ;
}
public class ShapeFactory extends AbstractFactory {
    
   @Override
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
   
   @Override
   public Color getColor(String color) {
      return null;
   }
}
public class ColorFactory extends AbstractFactory {
    
   @Override
   public Shape getShape(String shapeType){
      return null;
   }
   
   @Override
   public Color getColor(String color) {
      if(color == null){
         return null;
      }        
      if(color.equalsIgnoreCase("RED")){
         return new Red();
      } else if(color.equalsIgnoreCase("GREEN")){
         return new Green();
      } else if(color.equalsIgnoreCase("BLUE")){
         return new Blue();
      }
      return null;
   }
}

判断创建哪一个工厂

public class FactoryProducer {
   public static AbstractFactory getFactory(String choice){
      if(choice.equalsIgnoreCase("SHAPE")){
         return new ShapeFactory();
      } else if(choice.equalsIgnoreCase("COLOR")){
         return new ColorFactory();
      }
      return null;
   }
}
public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {
 
      //获取形状工厂
      AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
 
      //获取形状为 Circle 的对象
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //调用 Circle 的 draw 方法
      shape1.draw();
 
      //获取形状为 Rectangle 的对象
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //调用 Rectangle 的 draw 方法
      shape2.draw();
      
      //获取形状为 Square 的对象
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //调用 Square 的 draw 方法
      shape3.draw();
 
      //获取颜色工厂
      AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
 
      //获取颜色为 Red 的对象
      Color color1 = colorFactory.getColor("RED");
 
      //调用 Red 的 fill 方法
      color1.fill();
 
      //获取颜色为 Green 的对象
      Color color2 = colorFactory.getColor("Green");
 
      //调用 Green 的 fill 方法
      color2.fill();
 
      //获取颜色为 Blue 的对象
      Color color3 = colorFactory.getColor("BLUE");
 
      //调用 Blue 的 fill 方法
      color3.fill();
   }
}

四、建造者模式
建造者模式也是创建型模式,不同于工厂模式的针对性创造,一种工厂生产一种商品。我们上面举的例子是汉堡店根据需求做哪种汉堡,或者冷饮。建造者模式就类似在店里点单,这个点单是任意的,不管汉堡还是冷饮都可以随意搭配点。下面看代码理解
代码示例:
这是一个食物条目接口

public interface Item {
   public String name();//名字
   public Packing packing();//包装
   public float price();    //价格
}

包装接口

public interface Packing {
   public String pack();
}

实现包装接口的类

public class Wrapper implements Packing {
 
   @Override
   public String pack() {
      return "Wrapper";
   }
}
public class Bottle implements Packing {
 
   @Override
   public String pack() {
      return "Bottle";
   }
}

实现食物接口(这里抽象方法为什么不实现接口中的name()方法,百思不得其解,还在查找资料)

public abstract class Burger implements Item {
 
   @Override
   public Packing packing() {
      return new Wrapper();
   }
 
   @Override
   public abstract float price();
}
public abstract class ColdDrink implements Item {
 
    @Override
    public Packing packing() {
       return new Bottle();
    }
 
    @Override
    public abstract float price();
}
public class VegBurger extends Burger {
 
   @Override
   public float price() {
      return 25.0f;
   }
 
   @Override
   public String name() {
      return "Veg Burger";
   }
}
public class ChickenBurger extends Burger {
 
   @Override
   public float price() {
      return 50.5f;
   }
 
   @Override
   public String name() {
      return "Chicken Burger";
   }
}
public class Coke extends ColdDrink {
 
   @Override
   public float price() {
      return 30.0f;
   }
 
   @Override
   public String name() {
      return "Coke";
   }
}
public class Pepsi extends ColdDrink {
 
   @Override
   public float price() {
      return 35.0f;
   }
 
   @Override
   public String name() {
      return "Pepsi";
   }
}
import java.util.ArrayList;
import java.util.List;
 
public class Meal {
 //定义为私有,不允许外部使用List,只能通过内部封装好的方法使用List
   private List<Item> items = new ArrayList<Item>();    
 
   public void addItem(Item item){
      items.add(item);
   }
 
   public float getCost(){
      float cost = 0.0f;
      for (Item item : items) {
         cost += item.price();
      }        
      return cost;
   }
 
   public void showItems(){
      for (Item item : items) {
         System.out.print("Item : "+item.name());
         System.out.print(", Packing : "+item.packing().pack());
         System.out.println(", Price : "+item.price());
      }        
   }    
}

这里就是一个点单的过程,把想添加的食物添加到集合中

public class MealBuilder {
 
   public Meal prepareVegMeal (){
      Meal meal = new Meal();
      meal.addItem(new VegBurger());
      meal.addItem(new Coke());
      return meal;
   }   
 
   public Meal prepareNonVegMeal (){
      Meal meal = new Meal();
      meal.addItem(new ChickenBurger());
      meal.addItem(new Pepsi());
      return meal;
   }
}

输出点单信息

public class BuilderPatternDemo {
   public static void main(String[] args) {
      MealBuilder mealBuilder = new MealBuilder();
 
      Meal vegMeal = mealBuilder.prepareVegMeal();
      System.out.println("Veg Meal");
      vegMeal.showItems();
      System.out.println("Total Cost: " +vegMeal.getCost());
 
      Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
      System.out.println("\n\nNon-Veg Meal");
      nonVegMeal.showItems();
      System.out.println("Total Cost: " +nonVegMeal.getCost());
   }
}

五、原型模式
用于创建重复对象,同时又能保证性能,在创建一个对象代价较大时可以采用这种模式,这种模式可以克隆对象,通俗的说就是可以复制一个对象。这个模式空口白话有点难以理解还是边看代码边理解。

创建一个类实现Cloneable接口,重写其中的clone方法,这一步操作就是克隆

public abstract class Shape implements Cloneable {
   
   private String id;
   protected String type;
   
   abstract void draw();
   
   public String getType(){
      return type;
   }
   
   public String getId() {
      return id;
   }
   
   public void setId(String id) {
      this.id = id;
   }
   
   public Object clone() {
      Object clone = null;
      try {
      //这一步就是实现了当前对象的克隆
         clone = super.clone();
      } catch (CloneNotSupportedException e) {
         e.printStackTrace();
      }
      return clone;
   }
}
public class Rectangle extends Shape {
 
   public Rectangle(){
     type = "Rectangle";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
public class Square extends Shape {
 
   public Square(){
     type = "Square";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class Circle extends Shape {
 
   public Circle(){
     type = "Circle";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}
import java.util.Hashtable;
 
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();
   }
 
   // 对每种形状都运行数据库查询,并创建该形状
   // shapeMap.put(shapeKey, shape);
   // 例如,我们要添加三种形状
   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);
 
      Rectangle rectangle = new Rectangle();
      rectangle.setId("3");
      shapeMap.put(rectangle.getId(),rectangle);
   }
}

输出的是克隆对象

public class PrototypePatternDemo {
   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());        
   }
}

这个是我目前学习耗时最多的一个,为了方便克隆的理解我还找了另一段代码
实现接口Cloneable不重写clone方法直接调用clone方法所克隆的对象在原对象改变时也会跟着改变,即浅复制;写clone方法后,克隆对象不会跟着原对象变化,即深复制

public class CloneTest implements Cloneable{

    private byte[] a = {1, 2, 3, 4};
    private byte[] b = {5, 6, 7, 8};
    
    public CloneTest clone() {
        CloneTest copy = null;
        try {
            copy = (CloneTest) super.clone();
            copy.a = this.a.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return copy;
    }
    
    public byte[] getA() {
        return this.a;
    }
    
    public byte[] getB() {
        return this.b;
    }

    public static void main(String[] args) {
        CloneTest original = new CloneTest();
        CloneTest cloned = original.clone();
        
        System.out.println("original.a == cloned.a : " + (original.getA() == cloned.getA()));
        System.out.println("cloned.a[3] = " + cloned.getA()[3]);
        
        original.getA()[3] = 9;
        System.out.println("cloned.a[3] = " + cloned.getA()[3]);
        
        System.out.println("original.b == cloned.b : " + (original.getB() == cloned.getB()));
        System.out.println("cloned.b[3] = " + cloned.getB()[3]);
        
        original.b[3] = 10;
        System.out.println("cloned.b[3] = " + cloned.getB()[3]);
    }

}

输出结果

original.a == cloned.a : false
cloned.a[3] = 4
cloned.a[3] = 4
original.b == cloned.b : true
cloned.b[3] = 8
cloned.b[3] = 10

待续。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值