- 保证整个应用中某个实例只有一个,需考虑多线程的情形。
- 根据不同的实现方式分成懒汉模式、饿汉模式、枚举和内部静态类。
- 补充说明 synchronized,详见SynchronizedSample
- 一般情况下直接使用饿汉模式就好了,如果明确要求要懒加载(lazy initialization)会倾向于使用静态内部类,如果涉及到反序列化创建对象时会试着使用枚举的方式来实现单例。
private static void testSingleton() {
BillPughSingleton bInstance1 = BillPughSingleton.getInstance();
// bInstance1.print();
EagerInitializingSingleton eInstance1 = EagerInitializingSingleton.getInstance();
// eInstance1.print();
EnumSingleton eunm1 = EnumSingleton.INSTANCE;
// eInstance1.print();
LazyInitializingSingleton lInstance1 = LazyInitializingSingleton.getInstance();
// lInstance1.print();
SafeLazyInitializingSingleton sInstance1 = SafeLazyInitializingSingleton.getInstance();
// sInstance1.print();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
BillPughSingleton bInstance2 = BillPughSingleton.getInstance();
EagerInitializingSingleton eInstance2 = EagerInitializingSingleton.getInstance();
EnumSingleton eunm2 = EnumSingleton.INSTANCE;
LazyInitializingSingleton lInstance2 = LazyInitializingSingleton.getInstance();
SafeLazyInitializingSingleton sInstance2 = SafeLazyInitializingSingleton.getInstance();
SingletonTest sTest = new SingletonTest();
if (bInstance1 == bInstance2 && bInstance1 == sTest.getBillPughSingleton())
System.out.println("Singleton\tBillPughSingleton 同一个实例");
else
System.out.println("Singleton\tBillPughSingleton 不同实例");
if (eInstance1 == eInstance2 && eInstance1 == sTest.getEagerInitializingSingleton())
System.out.println("Singleton\tEagerInitializingSingleton 同一个实例");
else
System.out.println("Singleton\tEagerInitializingSingleton 不同实例");
if (eunm1 == eunm2 && eunm1 == sTest.getEnumSingleton())
System.out.println("Singleton\tEnumSingleton 同一个实例");
else
System.out.println("Singleton\tEnumSingleton 不同实例");
if (lInstance1 == lInstance2 && lInstance1 == sTest.getLazyInitializingSingleton())
System.out.println("Singleton\tLazyInitializingSingleton 同一个实例");
else
System.out.println("Singleton\tLazyInitializingSingleton 不同实例");
if (sInstance1 == sInstance2 && sInstance1 == sTest.getSafeLazyInitializingSingleton())
System.out.println("Singleton\tSafeLazyInitializingSingleton 同一个实例");
else
System.out.println("Singleton\tSafeLazyInitializingSingleton 不同实例");
}
});
t.start();
}
private static void testFactory() {
ColorFactory cf = new ColorFactory();
cf.getColor(ColorFactory.BLUE).onDraw();
cf.getColor(ColorFactory.RED).onDraw();
}
- 抽象工厂用在有大量工厂时,大致上与工厂模式一样,可理解成超级工厂模式。
- super factory内有各式工厂,工厂内部运作同工厂模式。
private static void testAbstractFactory() {
CarFactory cf = new CarFactory();
cf.getColor(CarFactory.RED).onDraw();
cf.getBrand(CarFactory.BENTLEY).show();
}
private static void testBuilder() {
RobotDirector rd = new RobotDirector(new OldStyleRobotBuilder());
rd.makeRobot();
Robot robot = rd.getRobot();
System.out.println("Builder\t" + robot.getArms());
System.out.println("Builder\t" + robot.getHead());
System.out.println("Builder\t" + robot.getLegs());
System.out.println("Builder\t" + robot.getTorso());
}
- 假如物件创建时耗费大量资源,用户不希望每次使用时都要重新创建,用prototype模式可以只创建一次,以后要用都用克隆。
- 其实就是拷贝的意思,但是不是返回内存地址的引用,而是一个拷贝的物件,拥有独立的内存空间。
- 用户通过ColorCache获取颜色,Blue2和Red2只需创建一次,每次存取时都是拿到克隆(返回本体的新拷贝,但无论如何本体都是安全的,不会被修改到)。
private static void testPrototype() {
try {
ColorCache colorCache = new ColorCache();
Color blue = colorCache.getColor(Type.BLUE);
blue.printID();
Color red1 = colorCache.getColor(Type.RED);
red1.printID();
Color red2 = colorCache.getColor(Type.RED);
red2.resetID();
red2.printID();
System.out.println(red1);
System.out.println(red2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
private static void testAdapter() {
MediaPlayer pc = new Computer();
pc.play();
MediaPlayer br = new Blu_ray_disc_player();
br.play();
}
- 举个例,假如用户要购买一辆新车,他选择任意的车型与颜色再结账(呼叫BuyerSGuide的addToCart()),所以在建构模组时,实作ColorSet和Garage的接口。
- 工厂模式是一个产品,自己只是提出来需要厂家生产,而桥接模式则是自己的产品去调用某个对象里的某个方法而已。这就是区别。最典型的例子就是JDBC。JDBC API(Sun)提供抽象部分,各个JDBC驱动厂商(Oracle, Mysql...)提供实现部分。新的JDBC驱动可以“即插即用”在JDBC API中,而不需要修改我们调用者的代码。这就是所谓的抽象部分(JDBC API)与它的实现部分(JDBC Driver)分离。从宏观角度JDBC可以称为桥模式。
private static void testBridge() {
BuyerSGuide bSGuide = new BuyerSGuide(new Hybids_N_Electric_Vehicle(), new Black());
bSGuide.addToCart();
}
private static void testFilter() {
List<Person> persons = new ArrayList<>();
persons.add(new Person("Robert", "Male", "Single"));
persons.add(new Person("John", "Male", "Married"));
persons.add(new Person("Laura", "Female", "Married"));
persons.add(new Person("Diana", "Female", "Single"));
persons.add(new Person("Mike", "Male", "Single"));
persons.add(new Person("Bobby", "Male", "Single"));
Criteria single = new CriteriaSingle();
System.out.println("Single:" + single.meetCriteria(persons));
Criteria women = new CriteriaFemale();
System.out.println("Women:" + women.meetCriteria(persons));
Criteria singleWomen = new AndCriteria(single, women);
System.out.println("Single Women:" + singleWomen.meetCriteria(persons));
Criteria married = new CriteriaMarried();
System.out.println("Married:" + married.meetCriteria(persons));
Criteria men = new CriteriaMale();
System.out.println("Men:" + men.meetCriteria(persons));
Criteria marriedOrMen = new OrCriteria(married, men);
System.out.println("Married or Men:" + marriedOrMen.meetCriteria(persons));
}
- 简言之,树状结构,用List < List > 实现。
public static void testComposite() {
Employee ceo = new Employee("Catherine", "CEO", 100000);
Employee headSales = new Employee("Conan", "Head sales", 80000);
Employee headMarketing = new Employee("Jordan", "Head marketing", 80000);
Employee sales1 = new Employee("Elsa", "Sales", 40000);
Employee sales2 = new Employee("Anna", "Sales", 40000);
Employee marketing = new Employee("Laura", "Marketing", 40000);
ceo.add(headMarketing);
ceo.add(headSales);
headMarketing.add(marketing);
headSales.add(sales1);
headSales.add(sales2);
System.out.println("CEO's subordinates:" + ceo.getSubordinates());
System.out.println("headSales' subordinates:" + headSales.getSubordinates());
System.out.println("headMarketing's subordinates:" + headMarketing.getSubordinates());
}
- 建立一个Car的接口,用各品牌去实现show(), 装饰者模式的用意在于不破坏本体的模组前提下,对其进行修改,比如升级音响、换轮胎等,有点类似补丁的概念。
- 必须实现本体是重点,见AbstractDecorator。
private static void testDecorator() {
Car tesla = new Tesla();
tesla.show();
System.out.print("normal Stereo System,\t");
System.out.print("normal Wheels,\t");
System.out.print("\n");
AbstractDecorator teslaWithNewStereo = new StereoSystem(tesla);
teslaWithNewStereo.show();
System.out.print("normal Wheels,\t");
System.out.print("\n");
AbstractDecorator teslaWithNewWheels = new Wheels(tesla);
teslaWithNewWheels.show();
System.out.print("normal Stereo System,\t");
System.out.print("\n");
AbstractDecorator teslaWithNewWheelsNStereo = new Wheels(teslaWithNewStereo);
teslaWithNewWheelsNStereo.show();
System.out.print("\n");
}
- 外观模式简单来说就是把内部实现的方法包装后再让用户呼叫(原本是用户直接呼叫),优点是未来内部实现的类有变动时,用户端可能可以不用更动。
- 比如呼叫Convertible或Coupe内部的方法原始做法会直接呼叫,但用外观模式的做法就会在两者外再包一层class,呼叫时是通过该class(CarFactory)。
private static void testFacade() {
com.catherine.facade.CarFactory cFactory = new com.catherine.facade.CarFactory();
cFactory.buildCoupe();
cFactory.buildConvertible();
}
- Flyweight模式的用意在于减少内存的使用。
- 好比要画出二十个圆形,总共只有五种颜色随意填充,在ShapeFactory创建一个HashMap并以颜色作为key,一共只需要创建五个物件。
private static void testFlyweight() {
final String[] colors = { "BLUE", "BLACK", "YELLOW", "GREEN", "WHITE" };
ShapeFactory sf = new ShapeFactory();
// 随机产生20个圆
for (int i = 0; i < 20; i++) {
Circle circle = sf.getCircle(colors[(int) (Math.random() * colors.length)]);
circle.setRadius((int) (Math.random() * 100));
circle.draw();
}
sf.debug();
}
- 假设我们要加载一张图,在ImageLoader初始化时加载,我们不希望每次加载同一张图都要重新创建一个ImageLoader(因为初始化费时之类的),利用一个ImageLoaderProxy来加载,一旦有了初始化过后的ImageLoader,就会用原先的ImageLoader物件继续操作。
private static void testProxy() {
ImageLoaderProxy imageLoader = new ImageLoaderProxy();
imageLoader.display();
imageLoader.display();
}
- 打印log时,权重最高的ERROR在较次的权重过滤器中都能打印,反之权重最低的DEBUG,在其它权重过滤器时都不会被打印。先设置Logger链,在用的时候一律执行ErrorLogger的实例,呼叫logMessage()时就会带入log级别。
private static void testChainOfResponsibility() {
// 先设置logger链,在用的时候一律执行ErrorLogger的实例,呼叫logMessage时就会带入log级别
Logger logger = new ErrorLogger();
Logger wLogger = new WarningLogger();
Logger dLogger = new DebugLogger();
logger.setNextLogger(wLogger);
wLogger.setNextLogger(dLogger);
// 真正开始测试
logger.logMessage(Logger.ERROR, "crash");
logger.logMessage(Logger.WARNING, "error pages");
logger.logMessage(Logger.DEBUG, "change color");
}
private static void testCommand() {
Command attack = new Attack();
Command jump = new Jump();
Command dodge = new Dodge();
Controller controller = new Controller();
System.out.print("Command: roll: ");
controller.add(dodge);
controller.add(jump);
controller.combos();
System.out.print("Command: aerial dash attack: ");
controller.add(jump);
controller.add(attack);
controller.combos();
}
private static void testInterpreter() {
Toolkits toolkits = new Toolkits();
Expression q1 = toolkits.getStates();
Expression q2 = toolkits.getVotingLimitation();
System.out.println("Interpreter: Is Beijing one of a state in the United States? " + q1.interpret("Beijing"));
System.out.println("Interpreter: Is Florida one of a state in the United States? " + q1.interpret("Florida"));
System.out.println("Interpreter: Am I eligible to vote? " + q2.interpret("I am a kid"));
System.out.println(
"Interpreter: Is Mom eligible to vote? " + q2.interpret("She is adult and she is a U.S. citizen"));
}
private static void testIterator() {
Sequence sequence = new Sequence();
System.out.print("Iterator: ");
for (Iterator iterator = sequence.getIterator(); iterator.hasNext();)
System.out.print(iterator.next() + " ");
System.out.print("\n");
}
- 原本是Main直接和ChatRoom通信,在中介者模式中加入一个中介者User避免上述两者直接沟通,好处是能把沟通的行为给封装,并且未来在代码维护时,可能比较不会改动到另一方。
private static void testMediator() {
User user = new User("A001", "Sev");
user.sendMessage("Hi there.");
}
private static void testMemento() {
Settings settings = new Settings();
World village1 = new World();
village1.setAmmo("Hunter arrow");
village1.setWeapon("Sharpshot bow");
village1.setXP(10000);
village1.setOutfit("Noar survivor");
int save1 = settings.save(village1.getState());
System.out.println(settings.loadLatest());
World village2 = new World();
village2.setAmmo("Fire arrow");
village2.setWeapon("War bow");
village2.setXP(20000);
village2.setOutfit("Shield weaver");
int save2 = settings.save(village2.getState());
System.out.println(settings.load(save1));
System.out.println(settings.load(save2));
}
private static void testObserver() {
BroadcastManager manager = new BroadcastManager();
new BinaryObserver(manager);
new HexObserver(manager);
new OctalObserver(manager);
manager.setState(17);
manager.setState(300);
}
- 参考Android的LocalBroadcastManager,同观察者模式,做了些调整,让用户自定义观察者收到的信息和之后的行为。
- 原先的观察者模式,收到通知后都是在个别实现观察者接口的类别里做不同的处理,改成用Receiver接口,让注册观察者(或理解为广播)的对象自行处理。
private static void testObserverPlus() {
com.catherine.observer_premium.BroadcastManager manager = new com.catherine.observer_premium.BroadcastManager();
manager.register(new Receiver() {
@Override
public void onReceive(String content) {
System.out.println(String.format("Observer plus: (Main1)%s", content));
}
});
manager.register(new Receiver() {
@Override
public void onReceive(String content) {
System.out.println(String.format("Observer plus: (Main2)%s", content));
}
});
ObserverPlusTest observerPlusTest = new ObserverPlusTest();
observerPlusTest.registerReceiver();
manager.sendMessage("Wake up!");
observerPlusTest.unregisterReceiver();
manager.sendMessage("Hurry!");
}
private static void testState() {
Gear g = new Gear1();
System.out.println(g.getState());
g = new Gear2();
System.out.println(g.getState());
g = new GearR();
System.out.println(g.getState());
}
private static void testNullObject() {
IDChecker idChecker = new IDChecker();
System.out.println(idChecker.getName("12351"));
System.out.println(idChecker.getName("10000"));
System.out.println(idChecker.getName("62343"));
System.out.println(idChecker.getName("20000"));
System.out.println(idChecker.getName("34261"));
}
private static void testStrategy() {
Calculator calculator = new Calculator(new OperationAdd());
System.out.println("4 + 5 = " + calculator.execute(4, 5));
calculator = new Calculator(new OperationSubstract());
System.out.println("4 - 5 = " + calculator.execute(4, 5));
calculator = new Calculator(new OperationMultiply());
System.out.println("4 * 5 = " + calculator.execute(4, 5));
}
- 以程序化购买为例,每个阶段都会有些许不同,但是整体来说都是一样的步骤。
- 两个要点:1. 分别实作每个阶段;2. 用final定义模版方法(整体流程)
- 在ProgrammaticBuying定义每个抽象方法,再定义一个final的方法buyAds(),把每个步骤都写入(固定流程),如此只需要其它class实现抽象方法,所以,在程序化购买上Blizzard和Supercell的流程都一样,都是呼叫buyAds(),但是其中每个步骤的细节就是自行定义的。
private static void testTemplate() {
Supercell supercell = new Supercell();
supercell.buyAds();
System.out.println("");
Blizzard blizzard = new Blizzard();
blizzard.buyAds();
}
- 有一种情况是类,以PrivateLevel为例,内部某个方法showInfo()须常常修改,扩充这个方法只会改动方法内部的变量,和自身的类没啥关系,同时该类也很庞大或者复杂,希望在改动方法时尽量避免改到该类,可以通过访问者模式处理,让方法内部的实现在另一个类RetrieveMethod中处理,未来每次修改只需要更动RetrieveMethod。
private static void testVisitor() {
System.out.println("Private");
AccessLevel level = new PrivateLevel();
level.showInfo(new RetrieveMethod());
System.out.println("Protected");
level = new ProtectedLevel();
level.showInfo(new RetrieveMethod());
System.out.println("Public");
level = new PublicLevel();
level.showInfo(new RetrieveMethod());
}
private static void testMVC() {
RetrieveCouponFromDB rc = new RetrieveCouponFromDB();
rc.downloadCoupons();
// click an item
String ID = "0001";
rc.downloadCouponDetail(ID);
// refresh
rc.downloadCoupons();
// click an item
ID = "0002";
rc.downloadCouponDetail(ID);
}
private static void testBusinessDelegate() {
BusinessDelegate bd = new BusinessDelegate(ServiceType.EJB);
Client client = new Client(bd);
client.createTask();
bd = new BusinessDelegate(ServiceType.JMS);
client = new Client(bd);
client.createTask();
}
private static void testCompositeEntity() {
Cashier cashier = new Cashier();
cashier.chectOut("white", "roast beef", "BBQ");
cashier.printReceipt();
cashier.chectOut("honey oat", "meatball", "olive oil & salt");
cashier.printReceipt();
}
- DAO(Data Access Object):通过DAO介面存取数据,这边本来有一个BlacklistDAO接口,并且由BlacklistDAOImpl实现,但是为了用单例模式解决多线程修改数据的问题直接省略BlacklistDAO接口。
- 用singleton避免多线程操作数据库——static方法+synchronized代码块可以保证无论有多少线程,同时只会有一个线程执行该方法,用同一把锁锁定代码块,可以保证同时只有一个线程执行一个代码块(多线程,多种方法做方法排程,一次只执行一种方法)
- 补充说明 synchronized,详见SynchronizedSample
private static void testDAO() {
BlacklistDAOImpl.getInstance();
Contact contact1 = new Contact();
contact1.setName("Zhang-San");
contact1.setBlock(Contact.BLOCK_PHONE_CALL);
Contact contact2 = new Contact();
contact2.setName("Li-Si");
contact2.setBlock(Contact.BLOCK_PHONE_CALL | Contact.BLOCK_SMS);
BlacklistDAOImpl.add(contact1);
BlacklistDAOImpl.add(contact2);
System.out.println(String.format("(%s)Add Zhang-San and Li-Si", Thread.currentThread().getName()));
List<Contact> blacklist = BlacklistDAOImpl.getBlacklist();
for (int i = 0; i < blacklist.size(); i++) {
System.out.println(String.format("(%s)%s", Thread.currentThread().getName(), blacklist.get(i)));
}
// test multiple treads
Thread t = new Thread(new Runnable() {
@Override
public void run() {
BlacklistDAOImpl.getInstance();
Contact contact3 = new Contact();
contact3.setName("Wang-Wu");
contact3.setBlock(Contact.BLOCK_PHONE_CALL | Contact.BLOCK_SMS);
BlacklistDAOImpl.add(contact3);
System.out
.println(String.format("(%s)Add Wang-Wu in another thread", Thread.currentThread().getName()));
List<Contact> blacklist = BlacklistDAOImpl.getBlacklist();
for (int i = 0; i < blacklist.size(); i++) {
System.out.println(String.format("(%s)%s", Thread.currentThread().getName(), blacklist.get(i)));
}
}
});
t.start();
Contact contact = blacklist.get(1);
System.out.println(String.format("(%s)Update Li-Si", Thread.currentThread().getName()));
contact.setName("Li-Si");
contact.setBlock(Contact.BLOCK_SMS);
BlacklistDAOImpl.update(contact);
blacklist = BlacklistDAOImpl.getBlacklist();
for (int i = 0; i < blacklist.size(); i++) {
System.out.println(String.format("(%s)%s", Thread.currentThread().getName(), blacklist.get(i)));
}
blacklist = BlacklistDAOImpl.getBlacklist();
System.out.println(
String.format("(%s)Delete _id=%d", Thread.currentThread().getName(), blacklist.get(1).getID()));
BlacklistDAOImpl.delete(blacklist.get(1).getID());
blacklist = BlacklistDAOImpl.getBlacklist();
for (int i = 0; i < blacklist.size(); i++) {
System.out.println(String.format("(%s)%s", Thread.currentThread().getName(), blacklist.get(i)));
}
}
private static void testFrontController() {
FrontController fController = new FrontController();
String token = null;
fController.dispatchView(token);
token = fController.inputCaptcha("XI0dk3");
fController.dispatchView(token);
token = fController.login("Oleg1234", "pw1234");
fController.dispatchView(token);
}
- 拦截过滤器模式通过过滤器链处理多过滤器,和过滤器模式一样自定义过滤器的接口让每个过滤的类别各自实现。
- 原始的逻辑是Main直接通过MusicPlayer呼叫getArtist(int),加入拦截过滤器后变成通过MusicPlayer呼叫getArtist(FilterManager, MemberInfo)。
private static void testInterceptingFilter() {
MemberInfo user1 = new MemberInfo();
user1.setID(1);
user1.setLevel(Level.BASIC);
user1.setName("0001");
user1.setCountry(Country.US);
MemberInfo user2 = new MemberInfo();
user2.setID(2);
user2.setLevel(Level.BASIC);
user2.setName("0002");
user2.setCountry(Country.UK);
MemberInfo user3 = new MemberInfo();
user3.setID(3);
user3.setLevel(Level.STANDARD);
user3.setName("0003");
user3.setCountry(Country.US);
MemberInfo user4 = new MemberInfo();
user4.setID(4);
user4.setLevel(Level.PRIMIUM);
user4.setName("0004");
user4.setCountry(Country.UK);
MemberInfo[] infos = new MemberInfo[] { user1, user2, user3, user4 };
MusicPlayer player = new MusicPlayer();
FilterManager fm = new FilterManager();
fm.addFilter(new LevelFilter(Level.BASIC));
fm.addFilter(new CountryFilter(Country.UK));
// fm.addFilter(new DebuggerFilter());
for (int i = 0; i < infos.length; i++) {
List<String> playlist = player.getArtist(fm, infos[i]);
if (playlist.size() != 0)
System.out.println(playlist);
}
}
private static void testServiceLocator() {
ServiceLocator s1 = new ServiceLocator();
Service pService1 = s1.lookup("playlist");
Service hService1 = s1.lookup("history");
System.out.println(pService1.response(1));
System.out.println(hService1.response(1));
ServiceLocator s2 = new ServiceLocator();
Service pService2 = s2.lookup("playlist");
Service hService2 = s2.lookup("history");
System.out.println(pService2.response(2));
System.out.println(hService2.response(2));
}
private static void testTransferObject() {
com.catherine.transfer_object.Employee Thomos = new com.catherine.transfer_object.Employee();
Thomos.setID(1);
Thomos.setName("Thomos");
Thomos.setDept("Present");
com.catherine.transfer_object.Employee Jeff = new com.catherine.transfer_object.Employee();
Jeff.setID(2);
Jeff.setName("Jeff");
Jeff.setDept("Director");
com.catherine.transfer_object.Employee Jonas = new com.catherine.transfer_object.Employee();
Jonas.setID(3);
Jonas.setName("Jonas");
Jonas.setDept("Marketing");
Studio studio = new Studio();
studio.addEmployee(Thomos);
studio.addEmployee(Jeff);
studio.addEmployee(Jonas);
studio.showAllStuff();
System.out.println("update Jonas");
studio.updateEmployee(3, "Head marketing");
studio.showAllStuff();
System.out.println("fire Thomos");
studio.fireEmployee(1);
studio.showAllStuff();
}
private static void testSynchronized() {
SynchronizedSample ss = new SynchronizedSample();
ss.testStaticParamsAsUsual();
ss.testStaticParams();
ss.testStaticParamsFromDifferentObj();
ss.testStaticMethod();
ss.testStaticMethodAndSyncCodes();
}
Copyright 2017 Catherine Chen (https://github.com/Catherine22)
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.