1、设计模式七大原则
- 单一职责原则
一个类只负责一项功能,在类或者方法(方法及其简单时)级别遵守单一职责原则 - 接口隔离原则
客户端不应该依赖他不需要的接口,即一个类对另一个类的依赖应该建立在最小接口之上 - 依赖倒置原则
- 高层模块不应该依赖底层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 依赖倒置的中心思想是面向接口编程
- 设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节搭建的架构要稳定的多。在Java中,抽象指的是接口或者抽象类,细节就是具体的实现类
- 使用接口或者抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现去完成
- 里氏替换原则
- 在子类中尽量不要重写父类的方法,在适当的情况下可以通过聚合,组合,依赖来解决问题。通常的做法是父类个子类继承 一个更通俗的基类。
- 开闭原则
- 软件的实体如类,方法,函数应该对扩展开放(开发者),对修改关闭(使用者)。
- 迪米特原则
- 一个类对自己依赖的类知道的越少越好,也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部,对外除了提供public方法,不对外泄露任何信息。核心就是降低类与类之间的耦合。
- 合成复用原则
- 原则是尽量使用合成/聚合的方式,而不是使用继承。
2、单例模式
所谓单例模式就是采用一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)
// 饿汉式
class Single{
// 构造器私有化
private Single(){}
// 类的内部创建对象
private static Single instance;
static {
instance = new Single();
}
// 向外暴露一个静态的公共方法
public static Single getInstance() {
return instance;
}
}
/**其他实现方式
懒汉式(静态代码块)
懒汉式(线程不安全)
懒汉式(线程安全,同步方法)
懒汉式(线程安全,同步代码块)
(推荐)双重检查
(推荐)静态内部类
(推荐)枚举
*/
3、工厂模式
主要解决:主要解决接口选择的问题。
何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
如何解决:在一个产品族里面,定义多个产品。
关键代码:在一个工厂里聚合多个同类产品。
(1)简单工厂模式
简单工厂模式:定义一个创建对象的类,由这个类来封装实例化对象的行为(代码)。比如:创建对象的实例时不要直接new,而是把这个new的动作放在一个工厂的方法中并返回。
//鼠标基类
class Mouse{
public void sayHi(){};
}
//鼠标扩展类
class DellMouse extends Mouse{
@Override
public void sayHi() {
System.out.println("产品:戴尔鼠标");
}
}
class HpMouse extends Mouse{
@Override
public void sayHi() {
System.out.println("产品:惠普鼠标");
}
}
//鼠标工厂
class MouseFactory{
//生产鼠标的方法,所有的鼠标都通过该方法生成
public static Mouse createMouse(int i) {
switch (i) {
case 0: return new DellMouse();
case 1: return new HpMouse();
default: return null;
}
}
}
public class NormFactory {
public static void main(String[] args) {
Mouse hpm = MouseFactory.createMouse(1);
Mouse dellm = MouseFactory.createMouse(0);
hpm.sayHi();
dellm.sayHi();
}
}
(2)工厂方法模式
定义一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类
class Mouse{
public void sayHi(){};
}
class DellMouse extends Mouse{
@Override
public void sayHi() {
System.out.println("产品:戴尔鼠标");
}
}
class HpMouse extends Mouse{
@Override
public void sayHi() {
System.out.println("产品:惠普鼠标");
}
}
//生产工厂接口
interface MouseFactory{
public Mouse createMouse();
}
//不同的鼠标交由不同的工厂生产
class HpMouseFactory implements MouseFactory{
@Override
public Mouse createMouse() {
return new HpMouse();
}
}
class DellMouseFactory implements MouseFactory{
@Override
public Mouse createMouse() {
return new DellMouse();
}
}
public class NormFactory {
public static void main(String[] args) {
MouseFactory hpFact = new HpMouseFactory();
MouseFactory dellFact = new DellMouseFactory();
Mouse hpm = hpFact.createMouse();
Mouse dellm = dellFact.createMouse();
hpm.sayHi();
dellm.sayHi();
}
}
(3)抽象工厂模式
class Mouse{
public void sayHi(){};
}
class DellMouse extends Mouse {
@Override
public void sayHi() {
System.out.println("产品:戴尔鼠标");
}
}
class HpMouse extends Mouse {
@Override
public void sayHi() {
System.out.println("产品:惠普鼠标");
}
}
class KeyBoard {
public void kick(){};
}
class HpKeyBoard extends KeyBoard {
@Override
public void kick() {
System.out.println("产品:惠普键盘");
}
}
class DellKeyBoard extends KeyBoard {
@Override
public void kick() {
System.out.println("产品:戴尔键盘");
}
}
//总的工厂接口
interface PcFactory {
public Mouse createMouse() ;
public KeyBoard createKeyBoard() ;
}
class HpFactory implements PcFactory {
@Override
public Mouse createMouse() {
return new HpMouse();
}
@Override
public KeyBoard createKeyBoard() {
return new HpKeyBoard();
}
}
class DellFactory implements PcFactory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
@Override
public KeyBoard createKeyBoard() {
return new DellKeyBoard();
}
}
//当需要增加一个华硕工厂时:
class AsusMouse extends Mouse {
@Override
public void sayHi() {
System.out.println("产品:华硕鼠标");
}
}
class AsusKeyBoard extends KeyBoard {
@Override
public void kick() {
System.out.println("产品:华硕键盘");
}
}
class AsusFactory implements PcFactory {
@Override
public Mouse createMouse() {
return new AsusMouse();
}
@Override
public KeyBoard createKeyBoard() {
return new AsusKeyBoard();
}
}
public class NormFactory {
public static void main(String[] args) {
PcFactory hpFact = new HpFactory();
Mouse hpm = hpFact.createMouse();
KeyBoard hpkbd = hpFact.createKeyBoard();
PcFactory dellFact = new DellFactory();
Mouse dellm = dellFact.createMouse();
KeyBoard dellkbd = dellFact.createKeyBoard();
hpm.sayHi();
dellm.sayHi();
hpkbd.kick();
dellkbd.kick();
}
}
// 侧重点在如何创建对象
4、适配器模式
适配器模式是一种结构型设计模式。适配器模式的思想是:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
适配器模式涉及三个角色:
- 源(Adaptee):需要被适配的对象或类型,相当于插头。
- 适配器(Adapter):连接目标和源的中间对象,相当于插头转换器。
- 目标(Target):期待得到的目标,相当于插座。
// 源
public class Adaptee {
public void method1(){
System.out.println("method 1");
}
}
// 目标
public interface Target {
void method1();
void method2();
}
// 适配器
public class Adapter extends Adaptee implements Target {
@Override
public void method2() {
System.out.println("method 2");
}
}
// 测试
class AdapterTest {
public static void main(String[] args) {
Adapter adapter = new Adapter();
adapter.method1();
adapter.method2();
}
}
5、策略模式
策略模式(Strategy Pattern)中,定义算法族(策略组),分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
策略模式涉及到的角色
-
运行环境类:Context,这个策略模式运行的环境,其实也就是在哪里使用
-
具体策略类:ConcreteStrategy,具体实现策略类
-
抽象策略类:Strategy,根据不同的需求,产生不同的策略或算法的接口
// 策略的接口
public interface Strategy {
public int operation(int num1,int num2);
}
// 具体的策略
public class Add implements Strategy {
@Override
public int operation(int num1, int num2) {
return num1 + num2;
}
}
// 具体的策略
public class Multiply implements Strategy {
@Override
public int operation(int num1, int num2) {
return num1 * num2;
}
}
// Context对象
public class Context {
// 聚合策略接口,为了使用它的实现方法
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
// 具体的调用方法
public int execute(int num1, int num2) {
return strategy.operation(num1, num2);
}
}
// 测试类
public class Client {
public static void main(String[] args) {
Context context = new Context(new Add());
System.out.println("加法:"+context.execute(1,1));
Context context1 = new Context(new Multiply());
System.out.println("乘法:" + context1.execute(2,3));
}
}
6、装饰者模式
装饰者模式的设计理念是以对客户端头透明的方式动态地扩充子类的功能,是继承关系的一个替代。(继承会产生大量的子类)
装饰者模式涉及到的角色
-
抽象构建角色(Component)通常是一个抽象类或者一个接口,定义了一系列方法,方法的实现可以由子类实现或者自己实现。通常不会直接使用该类,而是通过继承该类或者实现该接口来实现特定的功能。(例如,对于动物类,有一个抽象方法输出所有的功能,基本功能包括:呼吸,觅食,睡觉等等)
-
具体构建角色(Concrete Component)是Component的实现类,实现了对应的方法,它就是那个被装饰的类。(具体构建角色可以建立很多个,例如狗,猫,鸟等等,如果是狗,我们可以装饰一些吼叫的功能,吃肉的功能;鸟可以装饰一些飞行的功能,带有翅膀的功能等等。当然这些需要在具体装饰角色中去具体定义)
-
装饰角色(Decorator)是Component的实现类,它是具体装饰角色共同实现的抽象类(也可以是接口),并且持有一个Component类型的对象引用,它的主要作用就是把客户端的调用委派到被装饰类。
-
具体装饰角色(Concrete Decorator)它是具体的装饰类,是Decorator的子类,当然也是Component的子类。它主要就是定义具体的装饰功能。对于狗这个具体构件角色而言,我们可以把吼叫,吃肉这两个功能定义成一个具体装饰角色。这样,如果我们再定义一个狼这样的具体构件角色的时候,就可以直接用具体装饰角色2来进行装饰。
// 抽象角色类
public interface Component {
void function();
}
// 具体构建角色(对应狗)
public class ConcreteComponent implements Component {
@Override
public void function() {
System.out.println("基本功能:呼吸+觅食+睡觉");
}
}
// 装饰角色
public class Decorator implements Component {
private Component component; //持有一个Component类型的对象引用
public Decorator(Component component) {
this.component = component;
}
@Override
public void function() {
component.function(); //客户端的调用委派给具体的子类
}
}
// 具体装饰角色(对应吼叫和吃肉这两个功能)
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
@Override
public void function() {
super.function();
System.out.println("附加功能:");
this.eat();
this.bellow();
}
private void eat() {
System.out.println("吃肉");
}
private void bellow() {
System.out.println("吼叫");
}
}
// 客户端测试类
public class ClientTest {
public static void main(String[] args) {
Component component = new ConcreteComponent();
System.out.println("------装饰前:-------");
component.function();
Component newComponent = new ConcreteDecorator(component);
System.out.println("------装饰后:-------");
newComponent.function();
}
}
//输出:
//------装饰前:-------
//基本功能:呼吸+觅食+睡觉
//------装饰后:-------
//基本功能:呼吸+觅食+睡觉
//附加功能:吃肉+吼叫