OO基础:
- 抽象
- 封装
- 多态
- 继承
OO设计特性:
- 可复用
- 可扩充
- 可维护
设计原则:
- 封装变化:把会变化的部分取出并“封装”起来,好让其他部分不会受到影响(找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起)
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
- 为了交互对象之间的松耦合设计而努力
- 类应该对扩展开放,对修改封闭
设计模式:
- 策略模式:定义了算法族,分别封装起来,让他们之前可以互相替换,此模式让算法的变化独立于使用算法的客户
- 观察者模式:定义了对象之前的一对多依赖,这样一来,对一个对象改变状态时,它的所有依赖者都会收到通知并自动更新(java也内置了观察者模式:参考java.util.Observer观察者接口、被观察者java.util.Observable接口)
- 装饰者模式:动态的将责任附加到对象上,若有扩展功能,装饰者提供了比继承更有弹性的替代方案(前提:装饰者和被装饰对象有相同的超类型)、(java中的io大量使用装饰者模式:)
- 简单工厂模式:简单工厂其实不是一个设计模式,反而更像一种编程习惯,定义一个生产工厂类,根据输入类型生产对应的产品(利用静态方法根据输入参数生成对应的产品,隐藏了产品实例化的细节),但是当用户需要新增产品ProductD时,必须在工厂类的生产方法中增加对应的判断分支,所以简单工厂模式违背了开放封闭原则
- 工厂模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类;符合开放封闭原则,但是由于每增加一个产品,都需要新增对应的生产工厂,导致增加额外的开发工作量
- 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类
- 单例模式:一个类只有一个实例,并提供一个全局访问点
- 适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间
难理解的模式下面给了示例,读者根据示例更容易理解一点
代码示例:
简单工厂模式:
简单工厂模式:
首先定义一个产品类的共同接口:
public interface Product{
//价格
int price();
//产品名
String getName();
}
分别有三个产品ProductA、ProductB、ProductC ,均实现Product接口:
public class ProductA implements Product {
@Override
public int price() {
return 100;
}
@Override
public String getName() {
return "ProductA";
}
}
public class ProductB implements Product {
@Override
public int price() {
return 200;
}
@Override
public String getName() {
return "ProductB";
}
}
public class ProductC implements Product {
@Override
public int price() {
return 300;
}
@Override
public String getName() {
return "ProductC";
}
}
定义一个生产工厂类,根据输入类型生产对应的产品:
public class Factory {
public static Product createProduct(String type){
Product product =null;
switch (type){
case "A":
product = new ProductA();
break;
case "B":
product = new ProductB();
break;
case "C":
product = new ProductC();
break;
}
return product;
}
}
工厂模式:
扫描二维码关注公众号,回复:
9231796 查看本文章
首先声明一个工厂接口,所有工厂必须实现这个接口:
public interface IFactory {
Product createProduct();
}
生产ProductA的工厂FactoryA:
public class FactoryA implements IFactory {
@Override
public Product createProduct() {
return new ProductA();
}
}
生产ProductB的工厂FactoryB:
public class FactoryB implements IFactory {
@Override
public Product createProduct() {
return new ProductB();
}
}
现在来根据新的工厂方法模式来生产:
IFactory factoryA = new FactoryA();
Product productA = factoryA.createProduct();
IFactory factoryB = new FactoryB();
Product productB = factoryB.createProduct();
抽象工厂模式:
假设现在需要针对每种产品生产对应的赠品,难道我们要新增一个Gift的生产工厂吗?其实没有必要,因为在这个场景下,每种产品必须附带了赠品,所以我们可以利用原有的工厂来生产赠品
先定一个共同的Gift接口:
public interface Gift {
String getGiftName();
}
增加GiftA、GiftB:
public class GiftA implements Gift {
@Override
public String getGiftName() {
return "GiftA";
}
}
修改Factory接口,增加生产Gift的方法:
public interface IFactory {
Product createProduct();
Gift createGift();
}
修改工厂方法模式下的FactoryA、FactoryB、FactoryC:
public class FactoryA implements IFactory {
@Override
public Gift createGift() {
return new GiftA();
}
@Override
public Product createProduct() {
return new ProductA();
}
}
生产产品和赠品:
IFactory factoryA = new FactoryA();
Product productA = factoryA.createProduct();
Gift giftA = factoryA.createGift();
装饰者模式:
以点餐为例,我在麦*劳点餐可以根据我需求增加食物种类和数量
抽象构件角色:
public interface Food {
String getDescription();
}
具体构件角色:
public class BasicSet implements Food{
@Override
public String getDescription() {
return "汉堡 + 可乐";
}
}
抽象装饰类角色:
public abstract class Decorator implements Food {
private Food food;
public Decorator(Food food) {
this.food = food;
}
@Override
public String getDescription() {
return this.food.getDescription();
}
}
具体装饰类角色:
public class FrenchFries extends Decorator {
public FrenchFries(Food food) {
super(food);
}
@Override
public String getDescription() {
return super.getDescription() + " + 薯条";
}
}
public class FriedChicken extends Decorator {
public FriedChicken(Food food) {
super(food);
}
@Override
public String getDescription() {
return super.getDescription() + " + 炸鸡";
}
}
public class IceCream extends Decorator {
public IceCream(Food food) {
super(food);
}
@Override
public String getDescription() {
return super.getDescription() + " + 冰淇淋";
}
}
测试类:
public class Test {
public static void main(String[] args) {
Food food = new BasicSet();
Decorator setMealA = new FrenchFries(food);
setMealA = new FrenchFries(setMealA);
setMealA = new FriedChicken(setMealA);
setMealA = new IceCream(setMealA);
System.out.println("套餐A:" + setMealA.getDescription());
}
}
输出结果:
套餐A:汉堡 + 可乐 + 薯条 + 薯条 + 炸鸡 + 冰淇淋
单例模式:
第一种(懒汉,线程不安全):这种写法lazy loading很明显,但是致命的是在多线程不能正常工作
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
第二种(懒汉,线程安全):这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
第三种(饿汉):
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
第四种(饿汉,变种):
public class Singleton {
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return this.instance;
}
}
第五种(静态内部类):
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理
第六种(双重校验锁):
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
为什么要加volatile关键字来修饰singleton对象?因为new Singleton()这块存在重排序的问题,可能导致单例非单例,加上volatile后能让jvm限制指令重排序,这样就没有问题了
适配器模式:
目标角色(PowerTarget.java):
public interface PowerTarget {
public int output5V();
}
适配者角色(PowerAdaptee.java):
public class PowerAdaptee {
private int output = 220;
public int output220V() {
System.out.println("电源输出电压:" + output);
return output;
}
}
适配器角色(PowerAdapter.java):
public class PowerAdapter implements PowerTarget{
private PowerAdaptee powerAdaptee;
public PowerAdapter(PowerAdaptee powerAdaptee) {
super();
this.powerAdaptee = powerAdaptee;
}
@Override
public int output5V() {
int output = powerAdaptee.output220V();
System.out.println("电源适配器开始工作,此时输出电压是:" + output);
output = output/44;
System.out.println("电源适配器工作完成,此时输出电压是:" + output);
return output;
}
}
参考文章: