设计模式(常用)

设计模式

六大原则

  • 单一职责原则
    就一个类而言,应该仅有一个引起它变化的原因。
    例如,在 Activity 中不应该存在 Bean 文件、网络数据处理以及列表的 Adapter。
  • 开放封闭原则
    类、模块、函数等应该是可以扩展的,但是不可修改。
    开放封闭原则有两个含义:一个是对于拓展是开放的,另一个是对于修改是封闭的。
  • 里氏替换原则
    所有引用基类(父类)的地方必须能够透明地使用其子类的对象。
  • 依赖倒置原则
    高层模块不应该依赖低层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
  • 迪米特原则
    一个软件实体应当尽可能少地与其他实体发生相互作用。
  • 接口隔离原则
    一个类对另一个类的依赖应该建立在最小的接口上。

设计模式分类

GoF 提出的设计模式总共有 23 种,根据目的准则分类,分为三大类。

  • 创建型设计模式,共 5 种:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。(创建对象)
  • 结构型设计模式,共 7 种:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 (对象的组成)
  • 行为型设计模式,共 11 种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。(对象的功能)

简单工厂模式

简单工厂模式属于创建型模式又叫做静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。

简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

简单工厂模式结构图

img

  • Factory:工厂类,简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
  • IProduct:抽象产品类,简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  • Product:具体产品类,是简单工厂模式的创建目标。

这里我们用生产电脑来举例,假设有一个电脑的代工生产商,它目前已经可以代工生产联想电脑了,随着业务的拓展,这个代工生产商还要生产惠普和华硕的电脑,这样我们就需要用一个单独的类来专门生产电脑,这就用到了简单工厂模式。下面我们来实现简单工厂模式:

创建抽象产品类

我们创建一个电脑的抽象产品类,他有一个抽象方法用于启动电脑:

public abstract class Computer {
    /**
     * 产品的抽象方法,由具体的产品类去实现
     */
    public abstract void start();
}

创建具体产品类

接着我们创建各个品牌的电脑,他们都继承了他们的父类Computer ,并实现了父类的start方法:

联想电脑:
public class LenovoComputer extends Computer{
    @Override
    public void start() {
        System.out.println("联想电脑启动");
    }
惠普电脑:
public class HpComputer extends Computer{
    @Override
    public void start() {
        System.out.println("惠普电脑启动");
    }
}
华硕电脑:
public class AsusComputer extends Computer {
    @Override
    public void start() {
        System.out.println("华硕电脑启动");
    }
}

创建工厂类

接下来创建一个工厂类,它提供了一个静态方法createComputer用来生产电脑。你只需要传入你想生产的电脑的品牌,它就会实例化相应品牌的电脑对象:

public class ComputerFactory {
    private ComputerFactory();//别人不能随便创建对象
    public static Computer createComputer(String type){
        
        if("lv".equals(type)){
              return new LenovoComputer();
        }else if("hp".equals(type)){
            return new HpComputer();
        }else if("asus".equals(type)){
            return new AsusComputer();
        }else{    
        return null;
        }
    }
}

客户端调用工厂类

客户端调用工厂类,传入“hp”生产出惠普电脑并调用该电脑对象的start方法:

public class CreatComputer {
    public static void main(String[]args){
      Computer c1 = ComputerFactory.createComputer("hp");
        if(c1 != null){
               c1.start()
        }else{
            System.out.println("暂时没有")
        }
     
    }
}

优点和缺点

优点
  • 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
  • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点
  • 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
  • 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,同样破坏了“开闭原则”;在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护
  • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构

适用环境

在以下情况下可以使用简单工厂模式:

  • 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数

模式应用

  • JDK类库中广泛使用了简单工厂模式,如工具类java.text.DateFormat,它用于格式化一个本地日期或者时间。
public final static DateFormat getDateInstance(); 
public final static DateFormat getDateInstance(int style); 
public final static DateFormat getDateInstance(int style,Locale locale);
  • 获取不同加密算法的密钥生成器。
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");

工厂方法模式

模式介绍

  • 工厂方法模式是一种简单的模式,在平时开发中应用很广泛,也许你不知道但已经使用了无数次该模式了,如android中的activity里的各个生命周期方法,以onCreate为例,它就可以看作一个工厂方法。
    我们在构造了一个ConstraintLayout布局里面有很多的子View,所有的视图最终都继承自View可以看作抽象产品,我们具体使用的View就是具体产品。我们使用的activity继承自Baseactivity,activity看作一个具体工厂,Baseactivity看作抽象工厂,通过其继承的onCreate方法最终创建布局,这就是工厂方法的含义。

**

定义与类型

  • 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行
  • 类型:创建型

使用场景

  • 创建对象需要大量重复的代码

  • 客户端不依赖于产品类实例如何被创建、实现的细节

  • 一个类通过子类来制定创建哪个对象

    优点

  • 用户只需要关心所需产品的对应工厂,无需关心细节

  • 加入新产品符合开闭原则,提高可扩展性

缺点

  • 类的个数容易过多,增加复杂度
  • 增加了系统的抽象性和理解难度

UML类图:

img

Factory_Method.png

工厂方法有4个对象:
抽象工厂类(Factory):提供抽象方法供具体工厂实现
具体工厂类(ConcreteFactory):提供具体的工厂
抽象产品类(Product):提供抽象方法供具体产品类实现
具体产品类(ConcreteProduct):提供具体的产品

使用步骤

步骤1: 创建抽象工厂类,定义具体工厂的公共接口;
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
步骤3: 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
**步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例

  • 抽象产品类:
public abstract class Video {
    public abstract void produce();
}
  • 具体产品类(ConcreteProduct)
public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("Python课程视频");
    }
}
public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("Java课程视频");
    }
}
  • 抽象工厂类:
public abstract class VideoFactory {
    public abstract Video getVideo();
}
  • 具体工厂类:
public class PythonVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }
}
public class JavaVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }
}
  • 客户端调用:
public static void main(String[] args) {
      VideoFactory vf = new PythonVideoFactory();
      Video v = vf.getVideo();
     v.produce();
  }
简单工厂在源码中的使用–Collection:
  • Collection(抽象工厂):
Iterator<E> iterator();
  • ArrayList(具体工厂):
 public Iterator<E> iterator() {
        return new Itr();
 }
  • Iterator(抽象产品):
public interface Iterator<E> {
    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}
  • Itr(具体产品):
  private class Itr implements Iterator<E> {
      int cursor;       // index of next element to return
      int lastRet = -1; // index of last element returned; -1 if no such
      int expectedModCount = modCount;

      Itr() {}

      public boolean hasNext() {
          return cursor != size;
      }
      '省略代码...'
  }

单例模式

保证类在内存中只有一个对象。

1、把构造方法私有

2、在成员位置自己创建一个对象

3、公共方法提供访问

饿汉式 :类一加载就造对象

public class StudentDemo {
	public static void main(String[] args) {
		
		Student s1 = Student.getStudent();
		Student s2 = Student.getStudent();
		System.out.println(s1 == s2);//true

	}
}
public class Student {
	
   //构造私有
	private Student() {
	}
	//不让外界修改
	private static Student s = new Student();
	//加静态保证外界访问
	public static Student getStudent() {
		return s;
	}
}

懒汉式:用的时候才创建对象

public class TeacherDemo {

	public static void main(String[] args) {
		Teacher t1 = Teacher.getTeacher();
		Teacher t2 = Teacher.getTeacher();
		System.out.println(t1 == t2);//true

	}

}
public class Teacher {
	private Teacher() {
	}
	private static Teacher t = null;
    //线程安全问题 要加同步
	public synchronized static Teacher getTeacher() {
		if(t == null) {
			t = new Teacher();
		}
		return t;
	}
}

img

体现:

Runtime类 饿汉式

调用dos命令

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值