工厂模式
什么是工厂模式 (Factory Pattern) ,顾名思义工厂就批量生产东西,工厂设计模式生产出来的东西当然就是类对象了。其主要的理念就是用户提出一个需求交由工厂予以生产,具体实现用户并不知晓。首先先来个示例说话,一天张三来到一家水果工厂要买罐头。首先这要是家生产罐头的工厂。
抽象出一个罐头接口其中一个简介方法。
public interface Can {
public void profile();
}
接下来看一下我们的罐头产品
public class Apple implements Can {
@Override
public void profile() {
System.out.println("这是一瓶苹果罐头");
}
}
public class Banana implements Can {
@Override
public void profile() {
System.out.println("这是一瓶香蕉罐头");
}
}
public class Pear implements Can {
@Override
public void profile() {
System.out.println("这是一瓶梨子罐头");
}
}
材料都齐备了接下来建设工厂了。
public class FruitFactory {
public static Can getFruit(String fruitName){
if("苹果".equals(fruitName)){
return new Apple();
}else if("香蕉".equals(fruitName)){
return new Pear();
}else if("梨子".equals(fruitName)){
return new Pear();
}
return null;
}
}
万丈高楼平地起,工厂完成。张三要来买水果罐头了,扯着嗓子要苹果和香蕉
public class Consumer {
public static void main(String[] args) {
//张三说了一声要梨子罐头,我们给了他一罐
Can can=FruitFactory.getFruit("苹果");
//张三拿起罐头一看简介好家伙正是他要的
can.profile();
//接着张三又说要香蕉的,随着又给了他一罐
Can can1=FruitFactory.getFruit("香蕉");
can1.profile();
}
}
张三定睛一瞧是个梨子罐头,一把薅住我的衣领说我店大欺客欺负他不知道罐头是怎么生产的,我顿时慌了,连声道歉对不起对不起是我大意了,并迅速修改了工厂生产的逻辑并加上枚举类做了优化。
我递给张三一张产品清单 CanEnum 让他照着点。
public enum CanEnum {
APPLE("苹果"),BANANA("香蕉"),PEAR("梨子");
String name;
CanEnum(String name) {
this.name = name;
}
}
public class FruitFactory {
public static Can getFruit(CanEnum canEnum){
if(CanEnum.APPLE==canEnum){
return new Apple();
}else if(CanEnum.BANANA==canEnum){
return new Banana();
}else if(CanEnum.PEAR==canEnum){
return new Pear();
}
return null;
}
}
张三照上次又来了一份,心满意足的离开了。
public class Consumer {
public static void main(String[] args) {
Can can=FruitFactory.getFruit(CanEnum.PEAR);
can.profile();
Can can1=FruitFactory.getFruit(CanEnum.BANANA);
can1.profile();
}
}
结合上述示例我们可以看出1.调用者想要一个具体的类只要知道名称即可,并不知道其具体的实现 2每增加一个产品就需要怎加一个实现类修改对象实现的工场或增加一个工厂,增加了系统的复杂度。一般复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入工厂类,会增加系统的复杂度,得不偿失。
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern),指工厂的工厂,是围绕一个超级工厂创建其他工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
咱们继续拿我们的工厂举例,现在发现纯生产罐头市场有限,并打算再拉一条饮料生产线投入饮料生产。
首先,抽象出瓶装饮料的接口
public interface Bottle {
void profile();
}
首先投入生产的是肥宅快乐水
public class Cola implements Bottle{
@Override
public void profile() {
System.out.println("这是一瓶可乐!");
}
}
接着就是雪碧
public class Sprite implements Bottle{
@Override
public void profile() {
System.out.println("这是一瓶雪碧");
}
}
最后是我国传统茶,前两种饮料糖分太多不健康,多喝喝茶健康优雅!下午三点当然饮茶先了,话说你是为了“老板梦”还是“老板的梦”奋斗?
public class Tea implements Bottle{
@Override
public void profile() {
System.out.println("这是一瓶茶");
}
}
且三种饮料都是瓶装都被贴上了各自的标签。
接下来就是撸起袖管搞咱的双产线工厂了,首先可以抽象出来我们的工厂主要就是生产罐头和瓶装饮料,然后实现它
public abstract class AbstractFactory {
abstract Bottle getDrink(DrinkEnum drinkEnum);
abstract Can getCan(CanEnum canEnum);
}
public class CurrentFactory extends AbstractFactory {
@Override
Bottle getDrink(DrinkEnum drinkEnum) {
if(DrinkEnum.COLA==drinkEnum){
return new Cola();
}else if(DrinkEnum.SPRITE==drinkEnum){
return new Sprite();
}else if(DrinkEnum.TEA==drinkEnum){
return new Tea();
}
return null;
}
@Override
Can getCan(CanEnum canEnum) {
if (CanEnum.APPLE == canEnum) {
return new Apple();
} else if (CanEnum.BANANA == canEnum) {
return new Banana();
} else if (CanEnum.PEAR == canEnum) {
return new Pear();
}
return null;
}
}
当然产品增加了我们也要增加一下产品单。
public enum DrinkEnum {
TEA("茶"),SPRITE("雪碧"),COLA("可乐");
String name;
DrinkEnum(String name) {
this.name = name;
}
}
接下来就开始消费了。
public class Conusmer {
public static void main(String[] args) {
AbstractFactory currentFactory = new CurrentFactory();
Bottle drink = currentFactory.getDrink(DrinkEnum.COLA);
drink.profile();
}
}
运行结果
再来上一罐苹果
public class Conusmer {
public static void main(String[] args) {
AbstractFactory currentFactory = new CurrentFactory();
Bottle drink = currentFactory.getDrink(DrinkEnum.COLA);
drink.profile();
Can can = currentFactory.getCan(CanEnum.APPLE);
can.profile();
}
}
单例模式
单例模式(Singleton Pattern)属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例。单例有多种实现方式。下面进行具体的介绍。
1. 饿汉式
顾名思义饿汉很饿需要立即有东西吃所以需要提前实例化对象,所以在类装载时实例化并且私有化构造器保障其不会被其他类实例化,是多线程安全的。其缺点也可以看出不管用不用都提前实例化了浪费了系统资源。
public class HungrySingleton {
private static final HungrySingleton hungrySingleton=new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getHungrySingleton(){
return hungrySingleton;
}
}
2. 懒汉式
懒汉式其思想也很好记,用时再实例化,当然也实例化一次。不要问为啥,问就是懒,我已经躺平了~。
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton(){}
public static LazySingleton getLazySingleton(){
if(lazySingleton==null){
lazySingleton=new LazySingleton();
}
return lazySingleton;
}
}
首先我们可以看到定义了属性但是并未赋值在我们获取单例对象是时进行是否实例化的判断,当然这种写法是多线程不安全的因此在多线程需要进行修改。
通过synchronize修饰方法从而使得线程安全,但是每次调用都会加锁会导致效率很低。
class LazySingleton1{
private static LazySingleton1 lazySingleton1;
private LazySingleton1(){}
public static synchronized LazySingleton1 getLazySingleton1(){
if (lazySingleton1==null){
lazySingleton1=new LazySingleton1();
}
return lazySingleton1;
}
}
所以可以使用双重检测锁机制,这样只会加锁一次 但是对象要用volatile进行修饰主要是为了防止指令重排序造成获得的对象不完整。
class LazySingleton2 {
private volatile static LazySingleton2 lazySingleton2;
private LazySingleton2(){}
public static LazySingleton2 getLazySingleton2(){
if(lazySingleton2==null) {
synchronized (LazySingleton2.class) {
if(lazySingleton2==null) {
lazySingleton2 = new LazySingleton2();
}
}
}
return lazySingleton2;
}
}
还有一种登记注册式,因其并未使用锁,相对实现并不复杂,这种方式能达到双检测锁方式一样的功效。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
class RegisterSingleton{
private static class SingletonHolder{
private static final RegisterSingleton registerSingleton=new RegisterSingleton();
}
private RegisterSingleton(){}
public static final RegisterSingleton getSingleton(){
return SingletonHolder.registerSingleton;
}
}
最后是枚举类型
public enum SingletonEnum {
SINGLETON;
public void doSomething(){
System.out.println("doSomething...");
}
}
其调用
public static void main(String[] args) {
SingletonEnum.SINGLETON.doSomething();
}
具体可以参考你知道吗?枚举单例模式是世界上最好的单例模式!!!
代理模式
代理模式(Proxy Pattern) 顾名思义指不直接调用通过代理对象调用,这种类型的设计模式属于结构型模式。
举例:继续上面我们提的工厂,现在我们不自己销售而是找代理商销售。
首先,我们要卖给代理人 马风,代理人马风也要卖给客户所以我们抽象出一个出售接口来获取价格。
public interface Sale {
BigDecimal price();
}

接着工厂进行销售,价格使用BigDecimal主要是防止精度丢失,虽然用来举例这里很鸡肋 。
public class FactorySale implements Sale {
private BigDecimal price;
public FactorySale(BigDecimal price) {
this.price = price;
}
@Override
public BigDecimal price() {
return price;
}
}
接着就是代理商了,代理商马风同样实现了Sale接口。但是其中通过调用工厂的销售,从而达到代理工厂销售给客户的最终目的,我们也同时注意到代理商马风在原先工厂销售的价格基础上又加了一笔价格也就是对原来的工厂中的price()方法进行了一次加强。
public class ProxySale implements Sale {
private FactorySale factorySale;
public ProxySale(FactorySale factorySale) {
this.factorySale = factorySale;
}
@Override
public BigDecimal price() {
BigDecimal profit = new BigDecimal("30");
BigDecimal price = factorySale.price();
return price.add(profit);
}
}
接着顾客张三他来了,以40的价格问代理商马风买了我们的产品。
public class Customer {
private static FactorySale factorySale = new FactorySale(new BigDecimal(10));
private static ProxySale proxySale = new ProxySale(factorySale);
public static void main(String[] args) {
BigDecimal price = proxySale.price();
System.out.println("代理商价格:"+price);
}
}
运行结果
过了几天,张三直接来工厂询问价格突然发现价格是真便宜,直接到工厂购买就没有中间商赚差价,马风是真的黑啊,
public class Customer {
private static FactorySale factorySale = new FactorySale(new BigDecimal(21));
private static ProxySale proxySale = new ProxySale(factorySale);
public static void main(String[] args) {
BigDecimal price = proxySale.price();
System.out.println("工厂价格:"+factorySale.price());
}
}
其他
待续loading…