Apache Isis: create dialog with referenced object dropdown - isis

Given an Apache Isis project with a simple domain model such as below, what are the absolute minimum requirements for a create dialogue that will display a dropdown selection of all available Offices when creating a new Person?
Current state: I can create an office objects, list all office objects, but when I want to create a Person, the create dialogue doesn't show a dropdown of the available offices, it just says "(none)" (see screenshot).
Currently my create dialogue for Person looks like this:
How can I display a dropdown of all available offices in this dialogue?
Here is a rough layout of the DOM code I have (JDO annotations omitted):
public class Office {
private String name;
// getter/setter ...
}
public class Person {
private String name;
private Office office;
// getter/setter...
}
and corresponding menu/repository classes such as
public class OfficeRepository {
public List<Office> listAll() {
// ...
}
}
public class PersonRepository {
public Person create(String name, final Office office) {
// ...
}
}
public class PersonMenu {
public static class CreateDomainEvent extends ActionDomainEvent<Person> {}
#Action(domainEvent = CreateDomainEvent.class)
public Person create(
#ParameterLayout(named="Name")
final String name,
final Office office) {
return personRepository.create(name, office);
}
}

You can use the choices supporting method, the autoComplete supporting method, or annotate the referenced class as #DomainObject(bounded=true). The latter is mostly appropriate for reference data objects with a limited (ie bounded) number of instances.
eg:
public List<Office> choices1Create()
return officerRepository.findAll();
}
See these apache isis docs for (links to) further detali.
If you have other questions, I recommend you sign up to the apache.isis mailing list.
Thx
Dan

Related

Which OO design to use when there is a limitation from a third-party system?

Imagine this scenario:
A Customer object that is provided by a third-party system which have multiple properties related to phone numbers.
public class Customer {
private String phoneAreaCode;
private String phoneNumber;
}
Another third-party system which receive his own Customer object which have a Phone object inside it.
public class XCustomer {
private Phone phone;
}
I would like to know if there is a OO design pattern to convert the Customer to XCustomer. Should one of the Customers know about the other Customer object and convert the phone properties into a Phone object? Should I create utility classes to convert one into another? Or there is a better solution?
Since both Customer and CustomerX classes come from third party so you can't modify Customer and CustomerX class.
I prefer a simple utility to do the conversion.
You can create Converter interface/implementation. This will be useful in DI environment or you want to have multi implementations
public interface CustomerConverter {
CustomerX convert(Customer customer);
}
public class CustomerConverterImpl implements CustomerConverter {
#Override
public CustomerX convert(Customer customer) {
// TODO convert
}
}

How to easily access widely different subsets of fields of related objects/DB tables?

Imagine we have a number of related objects (equivalently DB tables), for example:
public class Person {
private String name;
private Date birthday;
private int height;
private Job job;
private House house;
..
}
public class Job {
private String company;
private int salary;
..
}
public class House {
private Address address;
private int age;
private int numRooms;
..
}
public class Address {
private String town;
private String street;
..
}
How to best design a system for easily defining and accessing widely varying subsets of data on these objects/tables? Design patterns, pros and cons, are very welcome. I'm using Java, but this is a more general problem.
For example, I want to easily say:
I'd like some object with (Person.name, Person.height, Job.company, Address.street)
I'd like some object with (Job.company, House.numRooms, Address.town)
Etc.
Other assumptions:
We can assume that we're always getting a known structure of objects on the input, e.g. a Person with its Job, House, and Address.
The resulting object doesn't necessarily need to know the names of the fields it was constructed from, i.e. for subset defined as (Person.name, Person.height, Job.company, Address.street) it can be the array of Objects {"Joe Doe", 180, "ACompany Inc.", "Main Street"}.
The object/table hierarchy is complex, so there are hundreds of data fields.
There may be hundreds of subsets that need to be defined.
A minority of fields to obtain may be computed from actual fields, e.g. I may want to get a person's age, computed as (now().getYear() - Person.birtday.getYear()).
Here are some options I see:
A SQL view for each subset.
Minuses:
They will be almost the same for similar subsets. This is OK just for field names, but not great for the joins part, which could ideally be refactored out to a common place.
Less testable than a solution in code.
Using a DTO assembler, e.g. http://www.genericdtoassembler.org/
This could be used to flatten the complex structure of input objects into a single DTO.
Minuses:
I'm not sure how I'd then proceed to easily define subsets of fields on this DTO. Perhaps if I could somehow set the ones irrelevant to the current subset to null? Not sure how.
Not sure if I can do computed fields easily in this way.
A custom mapper I came up with.
Relevant code:
// The enum has a value for each field in the Person objects hierarchy
// that we may be interested in.
public enum DataField {
PERSON_NAME(new PersonNameExtractor()),
..
PERSON_AGE(new PersonAgeExtractor()),
..
COMPANY(new CompanyExtractor()),
..
}
// This is the container for field-value pairs from a given instance of
// the object hierarchy.
public class Vector {
private Map<DataField, Object> fields;
..
}
// Extractors know how to get the value for a given DataField
// from the object hierarchy. There's one extractor per each field.
public interface Extractor<T> {
public T extract(Person person);
}
public class PersonNameExtractor implements Extractor<String> {
public String extract(Person person) {
return person.getName();
}
}
public class PersonAgeExtractor implements Extractor<Integer> {
public int extract(Person person) {
return now().getYear() - person.getBirthday().getYear();
}
}
public class CompanyExtractor implements Extractor<String> {
public String extract(Person person) {
return person.getJob().getCompany();
}
}
// Building the Vector using all the fields from the DataField enum
// and the extractors.
public class FullVectorBuilder {
public Vector buildVector(Person person) {
Vector vector = new Vector();
for (DataField field : DataField.values()) {
vector.addField(field, field.getExtractor().extract(person));
}
return vector;
}
}
// Definition of a subset of fields on the Vector.
public interface Selector {
public List<DataField> getFields();
}
public class SampleSubsetSelector implements Selector {
private List<DataField> fields = ImmutableList.of(PERSON_NAME, COMPANY);
...
}
// Finally, a builder for the subset Vector, choosing only
// fields pointed to by the selector.
public class SubsetVectorBuilder {
public Vector buildSubsetVector(Vector fullVector, Selector selector) {
Vector subsetVector = new Vector();
for (DataField field : selector.getFields()) {
subsetVector.addField(field, fullVector.getValue(field));
}
return subsetVector;
}
}
Minuses:
Need to create a tiny Extractor class for each of hundreds of data fields.
This is a custom solution that I came up with, seems to work and I like it, but I feel this problem must have been encountered and solved before, likely in a better way.. Has it?
Edit
Each object knows how to turn itself into a Map of fields, keyed on an enum of all fields.
E.g.
public enum DataField {
PERSON_NAME,
..
PERSON_AGE,
..
COMPANY,
..
}
public class Person {
private String name;
private Date birthday;
private int height;
private Job job;
private House house;
..
public Map<DataField, Object> toMap() {
return ImmutableMap
.add(DataField.PERSON_NAME, name)
.add(DataField.BIRTHDAY, birthday)
.add(DataField.HEIGHT, height)
.add(DataField.AGE, now().getYear() - birthday.getYear())
.build();
}
}
Then, I could build a Vector combining all the Maps, and select subsets from it like in 3.
Minuses:
Enum name clashes, e.g. if Job has an Address and House has an Address, then I want to be able to specify a subset taking street name of both. But how do I then define the toMap() method in the Address class?
No obvious place to put code doing computed fields requiring data from more than one object, e.g. physical distance from Address of House to Address of Company.
Many thanks!
Over in-memory object mapping in the application, I would favor database processing of the data for better performance. Views, or more elaborate OLAP/datawarehouse tooling could do the trick. If the calculated fields remain basic, as in "age = now - birth", I see nothing wrong with having that logic in the DB.
On the code side, given the large number of DTOs you have to deal with, you could use classless dynamic (available in some JVM languages) or JSON objects. The idea is that when a data structure changes, you only need to modify the DB and the UI, saving you the cost of changing a whole bunch of classes in between.

Change ViewModel default data strictly from server in MVC?

I know this is a weird one but bear with me. I need to set a default state/value for form inputs on a portion of my application.
In my "MainController" I pull up a portion (or 'wrapper' of sorts) page and then pull partial views from this main page. Here's a pseudo-code example:
User goes to Main ->
MainController/Index Called
-> User clicks Link A ->
AJAX .load() pulls html from PartialViewA into #partialContainer
-> User clicks Link B ->
AJAX .load pulls html from PartialViewB into #partialContainer
Here's the AJAX call:
$("#mainPanel").load('#Url.Action("GetModule","Settings")' + '?partialName=' + moduleName);
...and the corresponding server-side action that handles it:
public ActionResult GetModule(string partialName)
{
return PartialView(partialName);
}
It works great for me, each of the modules has plenty of form fields on them, all interacting well with one another and server so that isn't my problem. The issue is setting default values from the dbase for the form fields contained in the partial views.
For instance the "General" partial has many checkboxes which will determine how portions of the application display. I want to pull from the database the pre-exisiting boolean value and when the partial gets pulled from GetModule(), have these values defaulted.
I've taken a look around and I'm afraid the way that I am pulling the partial's into the main page may be the issue. I thought I could build the defaults into the constructor like so:
public class GeneralViewModel
{
public GeneralViewModel()
{
var Data = from m in dataContext.Table
where m.UserID == _id
select new
{
m.Data1,
m.Data2,
};
foreach(var setting in Data)
{
Checkbox1 = Convert.ToBoolean(setting.Data1); // Conversion from bool? to bool
Checkbox2 = Convert.ToBoolean(setting.Data2); // Conversion from bool? to bool
}
}
public bool Checkbox1 { get; set; }
public bool Checkbox2 { get; set; }
}
But it would appear the constructor never gets called. That sort of makes sense, except when you consider the fact that my form fields are not only rendering properly, but communicating with the database just fine as well. So the question is, what am I doing wrong? Is it the way I call the Partial's or am I missing something with assigning values to my VM values?
As always, thanks SO!
I think it's better to have different action methods for rendering the partial views, but for your case, i think this solution would work.
Have a Model that contains the other view models
public class ViewModel
{
public ViewModel1 ViewModel1 { get;set;}
public GenereViewModel General {get;set;}
}
Then in your controller you could initialize the viewmodel based on the partial name.
public ActionResult GetModule(string partialName)
{
var model = new ViewModel();
switch (partialName)
{
case "General": model.General = InitializeGeneral();
break;
case "ViewModel1": model.ViewModel1 = InitializeViewModel1(); break;
}
return PartialView(partialName, model);
}
private GeneralViewModel InitializeGeneral()
{
// initalize then return model
}

adapter-Any real example of Adapter Pattern [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
I want to demonstrate use of Adapter Pattern to my team. I've read many books and articles online. Everyone is citing an example which are useful to understand the concept (Shape, Memory Card, Electronic Adapter etc.), but there is no real case study.
Can you please share any case study of Adapter Pattern?
p.s. I tried searching existing questions on stackoverflow, but did not find the answer so posting it as a new question. If you know there's already an answer for this, then please redirect.
Many examples of Adapter are trivial or unrealistic (Rectangle vs. LegacyRectangle, Ratchet vs. Socket, SquarePeg vs RoundPeg, Duck vs. Turkey). Worse, many don't show multiple Adapters for different Adaptees (someone cited Java's Arrays.asList as an example of the adapter pattern). Adapting an interface of only one class to work with another seems a weak example of the GoF Adapter pattern. This pattern uses inheritance and polymorphism, so one would expect a good example to show multiple implementations of adapters for different adaptees.
The best example I found is in Chapter 26 of Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development (3rd Edition). The following images are from the instructor material provided on an FTP site for the book.
The first one shows how an application can use multiple implementations (adaptees) that are functionally similar (e.g., tax calculators, accounting modules, credit authorization services, etc.) but have different APIs. We want to avoid hard-coding our domain-layer code to handle the different possible ways to calculate tax, post sales, authorize credit card requests, etc. Those are all external modules that might vary, and for which we can't modify the code. The adapter allows us to do the hard-coding in the adapter, whereas our domain-layer code always uses the same interface (the IWhateverAdapter interface).
We don't see in the above figure the actual adaptees. However, the following figure shows how a polymorphic call to postSale(...) in the IAccountingAdapter interface is made, which results in a posting of the sale via SOAP to an SAP system.
How to turn a french person into a normal person...
public interface IPerson
{
string Name { get; set; }
}
public interface IFrenchPerson
{
string Nom { get; set; }
}
public class Person : IPerson
{
public string Name { get; set; }
}
public class FrenchPerson : IFrenchPerson
{
public string Nom { get; set; }
}
// that is a service that we want to use with our French person
// we cannot or don't want to change the service contract
// therefore we need 'l'Adaptateur'
public class PersonService
{
public void PrintName(IPerson person)
{
Debug.Write(person.Name);
}
}
public class FrenchPersonAdapter : IPerson
{
private readonly IFrenchPerson frenchPerson;
public FrenchPersonAdapter(IFrenchPerson frenchPerson)
{
this.frenchPerson = frenchPerson;
}
public string Name
{
get { return frenchPerson.Nom; }
set { frenchPerson.Nom = value; }
}
}
Example
var service = new PersonService();
var person = new Person();
var frenchPerson = new FrenchPerson();
service.PrintName(person);
service.PrintName(new FrenchPersonAdapter(frenchPerson));
Convert an Interface into another Interface.
Any real example of Adapter Pattern
In order to connect power, we have different interfaces all over the world.
Using Adapter we can connect easily like wise.
Here is an example that simulates converting analog data to digit data.
It provides an adapter that converts float digit data to binary data, it's probably not useful in real world, it just helps to explain the concept of adapter pattern.
Code
AnalogSignal.java
package eric.designpattern.adapter;
public interface AnalogSignal {
float[] getAnalog();
void setAnalog(float[] analogData);
void printAnalog();
}
DigitSignal.java
package eric.designpattern.adapter;
public interface DigitSignal {
byte[] getDigit();
void setDigit(byte[] digitData);
void printDigit();
}
FloatAnalogSignal.java
package eric.designpattern.adapter;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FloatAnalogSignal implements AnalogSignal {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private float[] data;
public FloatAnalogSignal(float[] data) {
this.data = data;
}
#Override
public float[] getAnalog() {
return data;
}
#Override
public void setAnalog(float[] analogData) {
this.data = analogData;
}
#Override
public void printAnalog() {
logger.info("{}", Arrays.toString(getAnalog()));
}
}
BinDigitSignal.java
package eric.designpattern.adapter;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BinDigitSignal implements DigitSignal {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private byte[] data;
public BinDigitSignal(byte[] data) {
this.data = data;
}
#Override
public byte[] getDigit() {
return data;
}
#Override
public void setDigit(byte[] digitData) {
this.data = digitData;
}
#Override
public void printDigit() {
logger.info("{}", Arrays.toString(getDigit()));
}
}
AnalogToDigitAdapter.java
package eric.designpattern.adapter;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>
* Adapter - convert analog data to digit data.
* </p>
*
* #author eric
* #date Mar 8, 2016 1:07:00 PM
*/
public class AnalogToDigitAdapter implements DigitSignal {
public static final float DEFAULT_THRESHOLD_FLOAT_TO_BIN = 1.0f; // default threshold,
private Logger logger = LoggerFactory.getLogger(this.getClass());
private AnalogSignal analogSignal;
private byte[] digitData;
private float threshold;
private boolean cached;
public AnalogToDigitAdapter(AnalogSignal analogSignal) {
this(analogSignal, DEFAULT_THRESHOLD_FLOAT_TO_BIN);
}
public AnalogToDigitAdapter(AnalogSignal analogSignal, float threshold) {
this.analogSignal = analogSignal;
this.threshold = threshold;
this.cached = false;
}
#Override
public synchronized byte[] getDigit() {
if (!cached) {
float[] analogData = analogSignal.getAnalog();
int len = analogData.length;
digitData = new byte[len];
for (int i = 0; i < len; i++) {
digitData[i] = floatToByte(analogData[i]);
}
}
return digitData;
}
// not supported, should set the inner analog data instead,
#Override
public void setDigit(byte[] digitData) {
throw new UnsupportedOperationException();
}
public synchronized void setAnalogData(float[] analogData) {
invalidCache();
this.analogSignal.setAnalog(analogData);
}
public synchronized void invalidCache() {
cached = false;
digitData = null;
}
#Override
public void printDigit() {
logger.info("{}", Arrays.toString(getDigit()));
}
// float -> byte convert,
private byte floatToByte(float f) {
return (byte) (f >= threshold ? 1 : 0);
}
}
Code - Test case
AdapterTest.java
package eric.designpattern.adapter.test;
import java.util.Arrays;
import junit.framework.TestCase;
import org.junit.Test;
import eric.designpattern.adapter.AnalogSignal;
import eric.designpattern.adapter.AnalogToDigitAdapter;
import eric.designpattern.adapter.BinDigitSignal;
import eric.designpattern.adapter.DigitSignal;
import eric.designpattern.adapter.FloatAnalogSignal;
public class AdapterTest extends TestCase {
private float[] analogData = { 0.2f, 1.4f, 3.12f, 0.9f };
private byte[] binData = { 0, 1, 1, 0 };
private float[] analogData2 = { 1.2f, 1.4f, 0.12f, 0.9f };
#Test
public void testAdapter() {
AnalogSignal analogSignal = new FloatAnalogSignal(analogData);
analogSignal.printAnalog();
DigitSignal digitSignal = new BinDigitSignal(binData);
digitSignal.printDigit();
// adapter
AnalogToDigitAdapter adAdapter = new AnalogToDigitAdapter(analogSignal);
adAdapter.printDigit();
assertTrue(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit()));
adAdapter.setAnalogData(analogData2);
adAdapter.printDigit();
assertFalse(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit()));
}
}
Dependence - via maven
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
How to test
Just run the unit test.
Adapter pattern works as a bridge between two incompatible interfaces.
This pattern involves a single class called adapter which is
responsible for communication between two independent or incompatible
interfaces.
Real-world examples might be a language translator or a mobile charger. More here in this youtube video:
Youtube - Adapter Design pattern: Introduction
You can use the Adapter design pattern when you have to deal with different interfaces with similar behavior (which usually means classes with similar behavior but with different methods). An example of it would be a class to connect to a Samsung TV and another one to connect to a Sony TV. They will share common behavior like open menu, start playback, connect to a network and etc but each library will have a different implementation of it (with different method names and signatures). These different vendor specific implementations are called Adaptee in the UML diagrams.
So, in your code (called Client in the UML diagrams), instead of hard code the method calls of each vendor (or Adaptee), you could then create a generic interface (called Target in UML diagrams) to wrap these similar behaviors and work with only one type of object.
The Adapters will then implement the Target interface delegating its method calls to the Adaptees that are passed to the Adapters via constructor.
For you to realize this in Java code, I wrote a very simple project using exactly the same example mentioned above using adapters to deal with multiple smart TV interfaces. The code is small, well documented and self explanatory so dig on it to see how a real world implementation would look like.
Just download the code and import it to Eclipse (or your favorite IDE) as a Maven project. You can execute the code by running org.example.Main.java. Remember that the important thing here is to understand how classes and interfaces are assembled together to design the pattern. I also created some fake Adaptees in the package com.thirdparty.libs. Hope it helps!
https://github.com/Dannemann/java-design-patterns
Adapter design patterns helps in converting interface of one class into interface of client expects.
Example:
You have a service which returns weather (in celsius) by passing city name as a input value. Now, assume that your client wants to pass zipcode as input and expecting the temperature of the city in return. Here you need an adaptor to achieve this.
public interface IWetherFinder {
public double getTemperature(String cityName);
}
class WeatherFinder implements IWetherFinder{
#Override
public double getTemperature(String cityName){
return 40;
}
}
interface IWeatherFinderClient
{
public double getTemperature(String zipcode);
}
public class WeatherAdapter implements IWeatherFinderClient {
#Override
public double getTemperature(String zipcode) {
//method to get cityname by zipcode
String cityName = getCityName(zipcode);
//invoke actual service
IWetherFinder wetherFinder = new WeatherFinder();
return wetherFinder.getTemperature(cityName);
}
private String getCityName(String zipCode) {
return "Banaglore";
}
}
One Real example is Qt-Dbus.
The qt-dbus has a utility to generate the adaptor and interface code from the xml file provided. Here are the steps to do so.
1. Create the xml file - this xml file should have the interfaces
that can be viewed by the qdbus-view in the system either on
the system or session bus.
2.With the utility - qdbusxml2cpp , you generate the interface adaptor code.
This interface adaptor does the demarshalling of the data that is
received from the client. After demarshalling, it invokes the
user defined - custom methods ( we can say as adaptee).
3. At the client side, we generate the interface from the xml file.
This interface is invoked by the client. The interface does the
marshalling of the data and invokes the adaptor interface. As told
in the point number 2, the adaptor interface does the demarshalling
and calls the adaptee - user defined methods.
You can see the complete example of Qt-Dbus over here -
http://www.tune2wizard.com/linux-qt-signals-and-slots-qt-d-bus/
Use Adapter when you have an interface you cannot change, but which you need to use. See it as you're the new guy in an office and you can't make the gray-hairs follow your rules - you must adapt to theirs. Here is a real example from a real project I worked on sometime where the user interface is a given.
You have an application that read all the lines in a file into a List data structure and displayed them in a grid (let's call the underlying data store interface IDataStore). The user can navigate through these data by clicking the buttons "First page", "Previous page", "Next page", "Last Page". Everything works fine.
Now the application needs to be used with production logs which are too big to read into memory but the user still needs to navigate through it! One solution would be to implement a Cache that stores the first page, next, previous and last pages. What we want is when the user clicks "Next page", we return the page from the cache and update the cache; when they click last page, we return last page from cache. In the background we have a filestream doing all the magic. By so doing we only have four pages in memory as opposed to the entire file.
You can use an adapter to add this new cache feature to your application without the user noticing it. We extend the current IDataStore and call it CacheDataStore. If the file to load is big, we use CacheDataStore. When we make a request for First, Next, Previous and Last pages, the information is routed to our Cache.
And who knows, tomorrow the boss wants to start reading the files from a database table. All you do is still extend IDataStore to SQLDataStore as you did for Cache, setup the connection in the background. When they click Next page, you generate the necessary sql query to fetch the next couple hundred rows from the database.
Essentially, the original interface of the application did not change. We simply adapted modern and cool features to work it while preserving the legacy interface.
You can find a PHP implementation of the Adapter pattern used as a defense against injection attacks here:
http://www.php5dp.com/category/design-patterns/adapter-composition/
One of the interesting aspects of the Adapter pattern is that it comes in two flavors: A class adapter relying on multiple inheritance and an object adapter relying on composition. The above example relies on composition.
#Justice o's example does not talk about adapter pattern clearly. Extending his answer -
We have existing interface IDataStore that our consumer code uses and we cannot change it. Now we are asked to use a cool new class from XYZ library that does what we want to implement, but but but, we cannot change that class to extend our IDataStore, seen the problem already ?
Creating a new class - ADAPTER, that implements interface our consumer code expects, i.e. IDataStore and by using class from the library whose features we need to have - ADAPTEE, as a member in our ADAPTER, we can achieve what we wanted to.
As per “C# 3.0 Design Patterns” book by Judith Bishop, Apple used Adapter pattern to adapt Mac OS to work with Intel products (explained in Chapter # 4, excerpt here2)
C# 3.0 Design Patterns
Structural Patterns: Adapter and Façade
An example from Yii framework would be: Yii uses internally cache utilizing an interface
ICache.
https://www.yiiframework.com/doc/api/1.1/ICache
whose signature is like : -
abstract public boolean set(string $id, mixed $value, integer $expire=0, ICacheDependency $dependency=NULL)
abstract public mixed get(string $id)
Let's say, you would like to use inside a Yii project the symfony cache library
https://packagist.org/packages/symfony/cache with it's cache interface, by defining this service in Yii services components (service locator) configuration
https://github.com/symfony/cache-contracts/blob/master/CacheInterface.php
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null);
We see, symfony cache has an interface with only a get method, missing a set method and a different signature for a get method, as Symfony uses the get method also as a setter when supplying the second callable parameter.
As Yii core internally uses this Yii cache/interface, it's difficult (extending Yii/YiiBase) if not impossible at places , to rewrite the calls to that interface.
Plus Symfony cache is nor our class, so we can't rewrite it's interface to fit with the Yii cache interface.
So here comes the adapter pattern to rescue. We will write a mapping = an intermediate adapter which will map the Yii cache interface calls to Symfony cache interface
Would look like this
class YiiToSymfonyCacheAdapter implements \Yii\system\caching\ICache
{
private \Symfony\Contracts\Cache\CacheInterface $symfonyCache;
public function __construct(\Symfony\Contracts\Cache\CacheInterface $symfonyCache)
{
$this->symfonyCache = $symfonyCache;
}
public boolean set(string $id, mixed $value, integer $expire=0, ICacheDependency
$dependency=NULL)
{
// https://symfony.com/doc/current/cache.html
return $this->symfonyCache->get(
$id,
function($item) {
// some logic ..
return $value;
}
);
// https://github.com/symfony/cache/blob/master/Adapter/MemcachedAdapter.php
// if a class could be called statically, the adapter could call statically also eg. like this
// return \Symfony\Component\Cache\Adapter\MemcacheAdapter::get(
// $id,
// function($item) {
// // some logic ..
// return $value;
// }
);
}
public mixed get(string $id)
{
// https://github.com/symfony/cache/blob/master/Adapter/FilesystemAdapter.php
// if a class could be called statically, the adapter could call statically also eg. like this
// \Symfony\Component\Cache\Adapter\FileSystemAdapter::get($id)
return $this->symfonyCache->get($id)
}
}
A real example can be reporting documents in an application. Simple code as here.
Adapters i think are very useful for programming structure.
class WordAdaptee implements IReport{
public void report(String s) {
System.out.println(s +" Word");
}
}
class ExcellAdaptee implements IReport{
public void report(String s) {
System.out.println(s +" Excel");
}
}
class ReportAdapter implements IReport{
WordAdaptee wordAdaptee=new WordAdaptee();
#Override
public void report(String s) {
wordAdaptee.report(s);
}
}
interface IReport {
public void report(String s);
}
public class Main {
public static void main(String[] args) {
//create the interface that client wants
IReport iReport=new ReportAdapter();
//we want to write a report both from excel and world
iReport.report("Trial report1 with one adaptee"); //we can directly write the report if one adaptee is avaliable
//assume there are N adaptees so it is like in our example
IReport[] iReport2={new ExcellAdaptee(),new WordAdaptee()};
//here we can use Polymorphism here
for (int i = 0; i < iReport2.length; i++) {
iReport2[i].report("Trial report 2");
}
}
}
Results will be:
Trial report1 with one adaptee Word
Trial report 2 Excel
Trial report 2 Word
This is an example of adapter implementation:
interface NokiaInterface {
chargementNokia(x:boolean):void
}
class SamsungAdapter implements NokiaInterface {
//nokia chargement adapted to samsung
chargementNokia(x:boolean){
const old= new SamsungCharger();
let y:number = x ? 20 : 1;
old.charge(y);
}
}
class SamsungCharger {
charge(x:number){
console.log("chrgement x ==>", x);
}
}
function main() {
//charge samsung with nokia charger
const adapter = new SamsungAdapter();
adapter.chargementNokia(true);
}

Set non-injected parameters when importing objects using MEF

I have the following scenario in my Silverlight 4 application:
public class TheViewModel
{
[Import()]
public TheChild Child { get; set; }
}
[Export()]
public class TheChild
{
[ImportingConstructor()]
public TheChild(String myName, IAmTheService service) { ... }
}
[Export(typeof(IAmTheService))]
public class TheService : IAmTheService
{
public void DoSomething(String theName);
}
As you can see, TheChild's constructor requires one imported parameter and one static value that is context-sensitive (has to be provided by the parent). The string value cannot come from AppSettings, configuration, etc. and can only be provided by the current instance of the parent class (TheViewModel in this case).
As a rule-of-thumb, I've always approached dependency-injection as follows:
Required dependencies are satisfied through constructor injection
Optional dependencies are satisfied through property injection
The "myName" parameter is required so I would prefer to set it through the constructor but given the way MEF works, I realize this may have to change.
Can you tell me how you've handled this scenario and your thoughts behind the solution?
You can specify a specific import contract in conjunction with [ImportingConstructor]. For example:
[Export()]
public class TheChild
{
[ImportingConstructor()]
public TheChild([Import("MyName")] String myName, IAmTheService service) { ... }
Given that, an export of a string decorated with [Export("MyName")] will be required and used to fulfill the dependency. Any of the [Import] specifications should work in this case (ie: importing a subclass by type, importing by name, etc).